Live data from Hacker News

When did people favor composition over inheritance?

sicpers.info

41–50 of 218 posts

Re: When did people favor composition over inheritance?

#41
Each has its place. There's some things that inheritance makes possible, and some things that are best handled by composition. I use both, quite frequently.

It Depends™.

Composition can add a lot of complexity to a design, and give bugs a lot more corners to hide in, but inheritance can be such a clumsy tool, that it just shouldn't be used for some tasks.

That goes for almost everything in software. Becoming zealous about "The Only Correct Way" can be quite destructive.

Re: When did people favor composition over inheritance?

#43
An important point not mentioned by the article is that of "co-recursion" with inheritance (of implementation).

That is: an instance of a subclass calls a method defined on a parent class, which in turn may call a method that's been overridden by the subclass (or even another sub-subclass in the hierarchy) and that one in turn may call another parent method, and so on. It can easily become a pinball of calls around the hierarchy.

Add to that the fact that "objects" have state, and each class in the hierarchy may add more state, and modify state declared on parents. Perfect combinatory explosion of state and control-flow complexity.

I've seen this scenario way too many times in projects, and worse thing is: many developers think it's fine... and are even proud of navigating such a mess. Heck, many popular "frameworks" encourage this.

Basically: every time you modify a class, you must review the inner implementation of all other classes in the hierarchy, and call paths to ensure your change is safe. That's a horrendous way to write software, against the most basic principles of modularity and low coupling.

Re: When did people favor composition over inheritance?

#44
post #14

Earlier quoted context omitted.

There is a reason C++ devs and only C++ devs have nightmares of diamond inheritance. Oh the damage that language has done to a generation, but at least it is largely passed us now.

I'm spoiled by Python's incredibly sane inheritance and I always have to keep in mind that inheritance is a very different beast in other languages.

I'm always surprised by how arrogant and unaware Python developers are. JavaScript/C++/etc developers are quite honest about the flaws in their language. Python developers will stare a horrible flaw in their language and say "I see nothing... BTW JS sucks so hard.".

Let me give you just one example of Python's stupid implementation of inheritance.

In Python you can initialize a class with a constructor that's not even in the inheritance chain (sorry, inheritance tree because Python developers think multiple inheritance is a good idea).

    class A:
        def __init__(self):
            self.prop = 1

    class B:
        def __init__(self):
            self.prop = 2

    class C(A):
        def __init__(self):
            B.__init__(self)


    c = C()
    print(c.prop) # 2, no problem boss
And before you say "but no one does that", no, I've see that myself. Imagine you have a class that inherits from SteelMan but calls StealMan in it's constructor and Python's like "looks good to me".

I've seen horrors you people can't imagine.

* I've seen superclass constructors called multiple times.

* I've seen constructors called out of order.

* I've seen intentional skipping of constructors (with comments saying "we have to do this because blah blah blah)

* I've seen intentional skipping of your parent's constructor and instead calling your grandparent's constructor.

* And worst of all, calling constructors which aren't even in your inheritance chain.

And before you say "but that's just a dumb thing to do", that's the exact criticism of JS/C++. If you don't use any of the footguns of JS/C++, then they're flawless too.

Python developers would say "Hurr durr, did you know that if you add a object and an array in JS you get a boolean?", completely ignoring that that's a dumb thing to do, but Python developers will call superclass constructors that don't even belong to them and think nothing of it.

------------------------------

Oh, bonus point. I've see people creating a second constructor by calling `object.__new__(C)` instead of `C()` to avoid calling `C.__init__`. I didn't even know it was possible to construct an object while skipping its constructor, but dumb people know this and they use it.

Yes, instead of putting an if condition in the constructor Python developers in the wild, people who walk among us, who put their pants on one leg at a time like the rest of us, will call `object.__new__(C)` to construct a `C` object.

    def init_c():
        c2 = object.__new__(C)
        c2.prop2 = 'three'
        print(c2.__dict__, type(c2)) # {'prop2': 'three'} 
And Python developers will look at this and say "Wow, Python is so flawless".

Re: When did people favor composition over inheritance?

#45
post #43

An important point not mentioned by the article is that of "co-recursion" with inheritance (of implementation). That is: an instance of a subclass calls a method defined on a parent class, which in turn may call a method that's been overridden by the subclass (or even another sub-subclass in the hierarchy) and that one in turn may call another parent method, and so on. It can easily become a pinball of calls around t…

This is only the case when the language does not distinguish between methods that can be overridden versus those that cannot. C++ gives you the keyword "virtual" to put in front of each member function that you want to opt into this behavior, and in my experience people tend to give it some thought on which should be virtual. So I rarely have this issue in C++. But in languages like Python where everything is overridable, the issue you mention is very real.

Re: When did people favor composition over inheritance?

#46
post #44
post #14

Earlier quoted context omitted.

I'm spoiled by Python's incredibly sane inheritance and I always have to keep in mind that inheritance is a very different beast in other languages.

I'm always surprised by how arrogant and unaware Python developers are. JavaScript/C++/etc developers are quite honest about the flaws in their language. Python developers will stare a horrible flaw in their language and say "I see nothing... BTW JS sucks so hard.". Let me give you just one example of Python's stupid implementation of inheritance. In Python you can initialize a class with a constructor that's not eve…

1. Your first example is very much expected, so I don't know what's wrong here.

2. Your examples / post in general seems to be "people can break semantics and get to the internals just to do anything" which I agree is bad, but python works of the principle of "we're all consenting adults" and just because you can, doesn't mean you should.

I definitely don't consent to your code, and I wouldn't allow it to be merged in main.

If you or your team members have code like this, and it's regularly getting pushed into main, I think the issue is that you don't have safeguards for design or architecture

The difference with JavaScript "hurr durr add object and array" - is that it is not an architectural thing. That is a runtime / language semantics thing. One would be right to complain about that

Re: When did people favor composition over inheritance?

#47
post #44
post #14

Earlier quoted context omitted.

I'm spoiled by Python's incredibly sane inheritance and I always have to keep in mind that inheritance is a very different beast in other languages.

I'm always surprised by how arrogant and unaware Python developers are. JavaScript/C++/etc developers are quite honest about the flaws in their language. Python developers will stare a horrible flaw in their language and say "I see nothing... BTW JS sucks so hard.". Let me give you just one example of Python's stupid implementation of inheritance. In Python you can initialize a class with a constructor that's not eve…

Oh I've seen one team constructing an object while skipping the constructor for a class owned by another team. The second team responded by rewriting the class in C. It turns out you cannot call `object.__new__` if the class is written in native code. At least Python doesn't allow you to mess around when memory safety is at stake.

Re: When did people favor composition over inheritance?

#48
Gameplay logic inherently leans more towards composition, with a little hint of inheritance.

You can have players and monsters, which are all types of "characters" or "units", which is inheritance, but instead of having a separate FlyingPlayer and a separate FlyingMonster, which use the same code for flight, you could have a FlyingComponent, which is composition.

I've been going all in on composition and it's amazing for quickly implementing new gameplay ideas. For example, instead of a monolithic `Player` class you could have a `PlayerControlComponent` then you can move that between different characters to let the player control monsters, drones, etc.

Imagine instead of only Pac-Man being able to eat the pills, you could also give the ghosts the `PillEaterComponent` in some crazy special game modes :)

I've also been fantasizing about a hypothetical language that is built from the ground up for coding gameplay, that doesn't use the word "class" at all but something else that could be a hybrid of inheritance+composition.

Re: When did people favor composition over inheritance?

#49
post #30

"Composition" is a word that can mean several things, and without having read the original source I never really understood which version they mean. As a rule, I've always viewed "composition" as "gluing together things that don't know necessarily know about each other", and that definition works well enough, but that doesn't necessarily eliminate inheritance. So then I start thinking in less-useful, more abstract de…

I have always heard "prefer composition to inheritance" also referred to as "has a" instead of "is a." Meaning:

    class Dog : Animal; // inheritance 
    class Car: 
        Wheels wheels; // composition

Re: When did people favor composition over inheritance?

#50
post #45
post #43

An important point not mentioned by the article is that of "co-recursion" with inheritance (of implementation). That is: an instance of a subclass calls a method defined on a parent class, which in turn may call a method that's been overridden by the subclass (or even another sub-subclass in the hierarchy) and that one in turn may call another parent method, and so on. It can easily become a pinball of calls around t…

This is only the case when the language does not distinguish between methods that can be overridden versus those that cannot. C++ gives you the keyword "virtual" to put in front of each member function that you want to opt into this behavior, and in my experience people tend to give it some thought on which should be virtual. So I rarely have this issue in C++. But in languages like Python where everything is overrid…

Good point. In Java and many other languages you can opt out instead... which might make a big difference. Is it more of a "cultural" thing?... again, many frameworks encourage it by design, and so do many courses/tutorials... so those devs would be happy to put "virtual" everywhere in C++
Post reply on HN