Live data from Hacker News

Why composition is often better than inheritance

joostdevblog.blogspot.com

41–50 of 97 posts

Re: Why composition is often better than inheritance

#41
post #2

While it's a well-written article, it really seems like beating a dead horse. Composition over inheritance is a basic rule of OO programming, so much so that it has its own wikipedia page ( http://en.wikipedia.org/wiki/Composition_over_inheritance )

Many of us still learned about OO in school, where inheritance was all but beaten into us, and composition was not mentioned. And based on what I've seen in interviews, this is still a common model taught in school. Composition is in the process of winning as the default method of composing things together in OO (see, for instance, Go), but it has not won yet.

And on the topic of Go, note how most common OO languages in use still have more convenient support for inheritance than composition, where "inheritance" is one token in the right place but "composition" takes a lot more boilerplate because there's no support built in, or you have to add a third-party library to make the boilerplate go away. Again, changing over time, but languages change slowly.

Re: Why composition is often better than inheritance

#42
In this case I'd argue that the roles are a bit messy and Character has too much knowledge. Character should not know that physics objects can be updated, and certainly shouldn't be calling updatePhysics. You could end up with an updated Character interacting with a Character whose physics state hasn't been updated yet.

applyKnockback: Character -> Physics object -> Physics engine

updatePhysics: Physics engine -> Physics object -> Character new position (x, y)

updateCharacter: Character reacts to change

Re: Why composition is often better than inheritance

#43
post #31

Earlier quoted context omitted.

Mixins can be implemented in a variety of ways, they don't need to be unmodularly inlined into class/object definitions as in scala. Also, mixin-style inheritance is by definition linearized multiple inheritance (at least according to cook/bracha, things get weirder with the Gabriel/Common Lisp definition).

It's true that they can be implemented in the same way, but the idea remains the same. Seeing mixins as inheritance is a far narrower definition than held by most languages (or libraries) that implement them. Mixins don't put any requirements on the polymorphism of the object that implements them, which ordinary inheritance does. It's common to use the Flavors/Lisp defintion of mixins, but I'll make sure to read up o…

The Brache-Cook has only a simple view on Mixins in CLOS and Flavors. Actually the more interesting parts are not described. Instead they focus on problems they perceive, but which rarely play a role in practice.

Re: Why composition is often better than inheritance

#44
post #31

Earlier quoted context omitted.

It's true that they can be implemented in the same way, but the idea remains the same. Seeing mixins as inheritance is a far narrower definition than held by most languages (or libraries) that implement them. Mixins don't put any requirements on the polymorphism of the object that implements them, which ordinary inheritance does. It's common to use the Flavors/Lisp defintion of mixins, but I'll make sure to read up o…

There have been many implementations of mixins, and many that I'm aware of, like Scala, are inheritance based. The nice thing about mixin style inheritance is that inheritance becomes much more composable. The type of an object then is not its class, but the set of mixins it extends.

Scala's implementation is definitely an interesting and a valuable one. I'm not debating that inheritance-based mixins are useful, they definitely are. It's just that they aren't necessarily inheritance-based, and there are many implementations of mixins that aren't, so defining it as such is at best somewhat limited and at worst misleading.

On a side note: scala's implementation, internally, is composition-based, since they compile forwarding methods to static methods into the class. They add an interface for those forwarding methods, so it can be used for polymorphism (which is what allows the fun things) but for their system to qualify as mixins, that interface is not necessary. For a very quick reference about this, you can look at http://stackoverflow.com/questions/2557303/how-are-scala-tra...

Re: Why composition is often better than inheritance

#46
post #2

While it's a well-written article, it really seems like beating a dead horse. Composition over inheritance is a basic rule of OO programming, so much so that it has its own wikipedia page ( http://en.wikipedia.org/wiki/Composition_over_inheritance )

>While it's a well-written article, it really seems like beating a dead horse

I graduated college about 10 years ago, and I was never taught anything near composition over inheritance. I was told about inheritance, but had to learn from other coworkers and experience that composition is much favored over inheritance. Now I mentor a number of junior developers and they need to be told composition over inheritance often. This isn't a problem that has fixed itself, and it's most certainly not beating a dead horse when it needs to be repeated for so many young programmers.

This isn't just a problem with formal CS courses - code schools like Hacker School and Flatiron School have this issue as well. It seems more natural and intuitive to inherit than compose. So this horse needs to continue being being as it's very much alive.

Re: Why composition is often better than inheritance

#47
post #29

Earlier quoted context omitted.

With interfaces, the above example would look like this: from abc import ABCMeta class PhysicsobjectMixin(ABCMeta): @abstractmethod def update_physics(self): pass @abstractmethod def apply_konckback(self, force): pass @abstractmethod def get_position(self): pass class FightMixin(ABCMeta): @abstractmethod def attack(self): pass @abstractmethod def defend(self): pass class TalkMixin(ABCMeta): @abstractmethod def say_so…

It's not DRY, but then again, the chances of not overwriting, or more likely adding something to that method are pretty small when your project becomes more than an illustration of a principle. For example, what if you want to add custom animations any time your `Character` takes an action? Suddenly, all that boilerplate you "abstracted" away through mix-ins is back, with a vengeance. How about if your physics for a…

> For example, what if you want to add custom animations any time your `Character` takes an action?

What's wrong with this?

    class Character(PhysicsobjectMixin, FightMixin, TalkMixin):
        def attack(self):
            # custom attack animation here
            return super(Character, self).attack()

        def defend(self):
            # custom defend animation here
            return super(Character, self).defend()
For me, it's still clear that 'attack' and 'defend' extends the funcionality of the 'FightMixin'. I can see even the first glance, those are inherited methods, because they use super() (call parent methods)

> How about if your physics for a `Projectile` are different than for a `Pickup`?

You need to implement two classes anyway. I see two possibilities:

I. If you have to implement this kind of different physics behavior only for Projectile. (Maybe you don't even need a mixin.)

    class Projectile(object):
        def update_physics(self):
            pass
        
        def apply_konckback(self, force):
            pass

        def get_position(self):
            pass

II. If you have more Projectile-like objects, but they are not all the same.

   class FastMovingPhysicsobjectMixin(object):
        def update_physics(self):
            pass
        
        def apply_konckback(self, force):
            pass

        def get_position(self):
            pass


    class Projectile(FastMovingPhysicsobjectMixin):
        pass

    
    class Arrow(FastMovingPhysicsobjectMixin):
        pass

> What if your character suddenly picks up a Sling of Thrown Voices, and needs to apply conversation snippets to its projectiles?

Is this a weapon which doesn't shoot projectiles, but make damage with voice or what? :D Then I think it's totally different, because if Character can have all kinds of different weapons and those behave different ways, mixins don't fit here. I would rather implement that like this:

    class Sword(object):
        def attack(self):
            # swing

        def defend(self):
            # defend

    
    class SlingOfThrownVoices(object):
        def attack(self):
            # shout loudly

        def defend(self):
            # pssszt, be quiet
    

    class Character(PhysicsobjectMixin, TalkMixin):
        def __init__(self, weapon):
            self.weapon = weapon

        def attack(self):
            # custom attack animation here
            self.weapon.attack()

        def defend(self):
            # custom defend animation here
            self.weapon.defend()
then weapon can be instance of either Sword or SlingOfThrownVoices. Note that Mixins are still in use and no complicated inheritance problem occured even if you have hundreds of weapons.

Re: Why composition is often better than inheritance

#48
When I try to choose between the two, I often like to think if the object I try to inherit from is from the same domain/context and solves a related problem. In the example in the article a PhysicsObject solves the problem of calculating coordinates in space and from the beginning it was not designed as something to be used in the game by itself. While the character participates in the actual game and executes the game logic. The character does not 'inherit' from PhysicsObject, it merely knows that PhysicsObject represents it in the space.

Re: Why composition is often better than inheritance

#49
post #2

While it's a well-written article, it really seems like beating a dead horse. Composition over inheritance is a basic rule of OO programming, so much so that it has its own wikipedia page ( http://en.wikipedia.org/wiki/Composition_over_inheritance )

It's not a rule of OO programming; it's a useful guideline for using certain programming languages that purport to be OO.

Re: Why composition is often better than inheritance

#50
post #40

In Python, we use mixins. Mixins can only inherit from 'object' and nothing else, like this: class PhysicsobjectMixin(object): def update_physics(self): pass def apply_konckback(self, force): pass def get_position(self): pass class FightMixin(object): def attack(self): pass def defend(self): pass class TalkMixin(object): def say_something(self): pass class Character(PhysicsobjectMixin, FightMixin, TalkMixin): pass cl…

That's just normal multiple-inheritance. Nothing like mixins. Mixins would be if the classes actually contribute pieces which combine in an interesting way. Like a border-mixin added to a button class would add to the drawing and to the geometry of the object.

Actually some cases of mixins are equivalent to multiple inheritance.
Post reply on HN