5 ms·
I think the implementation in C++ put it out of fashion, as later languages (e.g. Java) deliberately restricted it to avoid the complexity. The main criticism
by mark_undoio 2y ago
I think the implementation in C++ put it out of fashion, as later languages (e.g. Java) deliberately restricted it to avoid the complexity. The main criticism I saw was the potential for (variants of) the "diamond" where A is subclassed by B and C, then both of those are subclassed by D. Does D get two copies of A's state? It's hard to come up with an intuitive behaviour.
More recently, the move seems to be away from class based object orientation (including inheritance) entirely.
On the other side of things, I've never heard people talk about Python's multiple inheritance with the same tone used for C++ - but then there are cultural differences in the language communities too.
- fiddlerwoaroof 2y agoSomething I’ve found interesting is that most widely-used class-based inheritance languages eventually added multiple inheritance of implementations back in: PHP added traits that can contain method implementations; Java added default implementations on interfaces; etc.
- lmm 2y agoThe famous "super considered harmful" post ( https://fuhm.net/super-harmful/ https://fuhm.net/super-harmful/ ) pointed out the key problem with diamonds, and it's mainly a problem with constructors. Allowing mixins that can have method implementations but only allowing one class parent with a constructor is a pretty good spot in the design space, and is what a lot of languages have converged on.
- fiddlerwoaroof 2y agoI like CL’s solution to constructors which is basically “specialize this generic function (SHARED-INITIALIZE or INITIALIZE-INSTANCE) with an :AFTER method”. You reliably run all the initialization code for each class involved and you don’t have to remember to call CALL-NEXT-METHOD (CL’s spelling of super) Edit: I see that post refers to Dylan, which is more like CL than python in the important ways. IMO, sleeping on CL’s object system CLOS was a huge mistake of the “Java/C++ era” of our industry.
- lmm 2y ago> I like CL’s solution to constructors which is basically “specialize this generic function (SHARED-INITIALIZE or INITIALIZE-INSTANCE) with an :AFTER method”. You reliably run all the initialization code for each class involved and you don’t have to remember to call CALL-NEXT-METHOD (CL’s spelling of super) The problem with implicitly calling a parent constructor is that the child then can't control when or how (and with what arguments) it runs. So it's really pick your poison; either the child controls the call, at the risk of doing it wrong or not at all, or it doesn't but then certain things become impossible. (Or does CL have ways to e.g. modify the arguments that the :AFTER method sees, or run something else after that runs?)
- fiddlerwoaroof 2y ago> So it's really pick your poison; either the child controls the call, at the risk of doing it wrong or not at all, or it doesn't but then certain things become impossible. CL lets you do both in various ways: the typical way to define a constructor is an :AFTER method that just sets the slots (fields in other languages) of the object and having a lot of behavior in constructors is unusual. You can also define an :AROUND method which would let a child class override the arguments passed to the constructor, with the downside that you can forget to CALL-NEXT-METHOD. However, CL's approach to object-orientation is pretty radically different from Python's. It's not a "kingdom of nouns" system where classes contain behavior and state but rather classes can contain state and behaviors are on equal footing with classes in the form of generic functions. (If you aren't familiar, I found skimming chapters 16+17 here[1] very enlightening when I was first learning CL). Classes in CL frequently don't contain any state at all and merely exist to pick out an implementation of a generic function to be used. Generic functions establish a web of relations between classes because they dispatch on every argument and not just a "this" parameter. [1]: https://gigamonkeys.com/book/ https://gigamonkeys.com/book/
- bitwize 2y ago> Does D get two copies of A's state? It's hard to come up with an intuitive behaviour. C++ gonna C++, which means the language covers all the bases because some programmer might get mad if their use case wasn't accounted for. C++ has something called virtual inheritance, wherein if subclasses B and C inherit virtually from A, any subclasses of both B and C will get one copy of A's state. Otherwise, they will get two copies: one from B and one from C. This solves the problem of addressing concerns of all programmers w.r.t. the diamond inheritance problem, but makes the language more complex (and triggers my CPPPTSD). https://en.wikipedia.org/wiki/Virtual_inheritance https://en.wikipedia.org/wiki/Virtual_inheritance
- pfdietz 2y agoIn this vein, note that Common Lisp's inheritance would always be virtual.