Inheritance is not a fundamental concept of anything. Inheritance is just composition with syntactic sugar. The semantic meaning was always composition. Oop is a mistake. Rust and pythons explicit self passing and turning of the dot operator into simple syntactic sugar is the correct approach. We should just stop teaching everything related to this in universities and go back to fundamentals.
Implementation inheritance is not just composition. Composition on its own does not allow for open recursion (implementing methods that were called on a base class in a derived class, via an in-built dispatch step), whereas inheritance does.
When did people favor composition over inheritance?
181–190 of 218 posts
Re: When did people favor composition over inheritance?
#182Earlier quoted context omitted.
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…
The virtual keyword in c++ is more of a compiler optimization and less of a design decision. C++ doesn't want everyone paying the overhead of virtual function calls like other languages
Of course these days with LTO the whole performance space is somewhat blurred since de-virtualisation can happen across whole applications at link time, and so the presumed performance cost can disappear (even if it wasn't actually a performance issue in reality). It's tough to create hard and fast rules in this case.
Re: When did people favor composition over inheritance?
#183What I like about the modern¹ approach (interfaces + composition) is that it cleanly untangles polymorphism from behaviour-sharing. When you inherit from a parent class, you have to be careful to only override methods in ways that the parent expects, so the parent's invariants aren't broken². There's a whole additional set of keywords (private/protected/final) meant to express these parent-child contracts. With inter…
> modern¹ approach (interfaces + composition) Smalltalk protocols and message categories were a step toward this (for example you could classify messages as implementing a particular interface, such as the collection or stream protocols), but Smalltalk lacked the type and interface checking supported by Java and other languages.
Re: When did people favor composition over inheritance?
#184Earlier quoted context omitted.
> It can easily become a pinball of calls around the hierarchy. This is why hierarchies should have limited depth. I'd argue some amount of "co-recursion" is to be expected: after all the point of the child class is to reuse logic of the parent but to overwrite some logic. But if the lineage goes too deep, it becomes hard to follow. > every time you modify a class, you must review the inner implementation of all othe…
> I'd argue some amount of "co-recursion" is to be expected: after all the point of the child class is to reuse logic of the parent That's the point: You can reuse code without paying that price of inheritance. You DON'T have to expect co-recursion or shared state just for "code-reuse". And, I think, is the key point: Behavior inheritance is NOT a good technique for code-reuse... Type-inheritance, however, IS good fo…
The same pinball of method calls happens at almost exactly the same way with composition.
You save some idiosyncrasies around the meaning of the object pointer, and that's all.
Re: When did people favor composition over inheritance?
#185Earlier quoted context omitted.
The problem in Rust is that if B is inside of A, struct A { name: String, owned: B } struct B { name: String, } you can't have a writeable reference to both A and B at the same time. This is alien to the way C/C++ programmers think. Yes, there are ways around it, but you spend a lot of time in Rust getting the ownership plumbing right to make this work.
It's kind of crazy that OOO is sold to people as 'thinking about the world as objects' and then people expect to have an object, randomly take out a part, do whatever they want with it and just stick it back in and voila This is honestly such an insane take when you think about what the physical analogue would be (which again, is how OOP is sold). The proper thing here is that, if A is the thing, then you really only…
Re: When did people favor composition over inheritance?
#186Earlier quoted context omitted.
Every language that permits diamond inheritance causes the devs who dare to use this feature at least some nightmare. It's not a C++ issue.
It's also cultural, possibily. Python supports diamond inheritance, and clearly states how it handles it (it ends up virtual in C++ terms). But in like 20 years of working with Python I can't remember encountering diamond inheritance in the wild once.
Then people noticed it was bad, and stopped.
Re: When did people favor composition over inheritance?
#187Earlier 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 haven't encountered diamond inheritance a single time in 10 years of writing/reading C++, so I definitely don't have nightmares about it. Maybe that was really a thing in the 90s or 2000s?
MI is not an issue in c++, and if it were the solution would be virtual inheritance.
Re: When did people favor composition over inheritance?
#188Earlier quoted context omitted.
It's also cultural, possibily. Python supports diamond inheritance, and clearly states how it handles it (it ends up virtual in C++ terms). But in like 20 years of working with Python I can't remember encountering diamond inheritance in the wild once.
Diamond inheritance is in fact highly pervasive in Python. The reason is that every class is a subclass of object since Python 3 (Python 2 allows classic classes that are different). So every single time you use multiple inheritance you have diamond inheritance. Some of this diamond inheritance is totally innocuous, but mostly not, because a lot of classes override dunder methods on object like __setattr__. It was Gu…
I don't think that's true, because...
> So every single time you use multiple inheritance you have diamond inheritance.
Multiple inheritance is supported but not itself “highly pervasive” in Python
> It was Guido van Rossum himself that observed the prevalence of diamond inheritance
The essay you link does not support that claim. He doesn’t observe an existing prevalence, he describes new features being added simultaneously with the MRO fix that would present new use cases where diamond inheritance may be useful.
And, its true, diamond inheritance is more common in modern Python than it was with classic classes in ancient Python, but there is a huge leap between that and “highly pervasive”.
Re: When did people favor composition over inheritance?
#189Each 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…
I dunno. It's easy to say, "there are trade-offs, it depends" any time two things are compared, and it's never entirely untrue. However, sometimes one option is just generally worse than the other. I'm not saying it's malpractice to use inheritance or anything, but it's a tool I definitely hesitate to reach for. Go and Rust removed inheritance entirely, and I'd say those languages are better-off without it.
¿Por qué no los dos?
Re: When did people favor composition over inheritance?
#190Earlier quoted context omitted.
I haven't encountered diamond inheritance a single time in 10 years of writing/reading C++, so I definitely don't have nightmares about it. Maybe that was really a thing in the 90s or 2000s?
I have been programming professionally in c++ for 20 years. I remember once thinking "cool, I could use virtual inheritance here". I ended up not needing it. MI is not an issue in c++, and if it were the solution would be virtual inheritance.
Some older C++ frameworks give all their objects a common base class. If that inheritance isn't virtual, developers may not be able to multiply inherit objects from that framework. That's fine, one can still inherit from classes outside the framework to "mix in" or add capabilities.
I've never understood the diamond pattern fear-mongering. It's just a rarely-encountered issue to keep in mind and handle appropriately.