4 ms·
I'm on the fence about inheritance myself; I often regret having used it, and I never regret having not used it. On the other hand, it's awfully expedient. I
by kragen 2y ago
I'm on the fence about inheritance myself; I often regret having used it, and I never regret having not used it. On the other hand, it's awfully expedient. I designed and implemented a programming language called Bicicleta whose only argument-passing mechanism is inheritance, and I'm not sure that was a bad idea.
The object-oriented part of OCaml, by the way, has inheritance that's entirely orthogonal to interfaces, which in OCaml are static types. Languages like Smalltalk and, for the most part, Python don't have interfaces at all.
- echelon 2y agoRigid, "family tree"-style inheritance as in classical OOP is pretty much garbage. "A cow is a mammal is an animal" is largely useless for the day to day work we do except in extremely well-planned, large and elaborate ontologies -- something you typically only see in highly structured software like windowing systems. It just isn't useful for the majority of our work. "Trait/Typeclass"-style compositional inheritance as in Rust and Haskell is sublime. It's similar to Java interfaces in terms of flexibility, and it doesn't enforce hierarchical rules [1]. You can bolt behaviors and their types onto structures at will. This is how OO should be. I put together a visual argument on another thread on HN a few weeks ago: https://imgur.com/a/class-inheritance-vs-traits-oop-isnt-bad-inheritance-is-bad-bmdUV3H https://imgur.com/a/class-inheritance-vs-traits-oop-isnt-bad... [1] Though if you want rules on bounds and associated types, you can have them.
- DaiPlusPlus 2y ago> "Trait/Typeclass"-style compositional inheritance as in Rust and Haskell is sublime. It's similar to Java interfaces in terms of flexibility, and it doesn't enforce hierarchical rules. Yes-and-no. Interfaces still participate in inheritance hierarchies (`interface Bar extends Foo`), and that's in a way that prohibits removing/subtracting type members (so interfaces are not in any way a substitute for mixins). Composition (of interfaces) can be used instead of `extends`, but then you lose guarantees of reference-identity - oh, and only reference-types can implement interfaces which makes interfaces impractical for scalars and unusable in a zero-heap-alloc program. Interface-types can only expose virtual members: no public fields - which seems silly to me because a vtable-like mechanism could be used to allow raw pointer access to fields via interfaces, but I digress: so many of these limitations (or unneeded functionality) are consequences of the JVM/CLR's design decisions which won't change in my lifetime. Rust-style traits are an overall improvement, yes - but (as far as my limited Rust experience tells me) there's no succinct way to tell the compiler to delegate the implementation of a trait to some composed type: I found myself needing to write an unexpectedly large amount of forwarding methods by hand (so I hope that Rust is better than this and that I was just doing Rust the-completely-wrong-way). Also, oblig: https://boxbase.org/entries/2020/aug/3/case-against-oop/ https://boxbase.org/entries/2020/aug/3/case-against-oop/
- int_19h 2y agoHow are interfaces with ability to provide default implementations for members (which both C# and Java allow today) not a substitute for mixins? "Only reference types can implement interfaces" is simply not true in C#. Not only can structs implement them, but they can also be used through the interface without boxing (via generics).
- AstralStorm 2y agoThey just cannot access any field in the class itself. Which means... the default implementations fail to actually implement anything but the simplest methods or you need to expose API-private things via getters violating open-closed principle. (If you merge multiple interfaces, the implementations of the methods have to match. You end up with even more special getters for each one sometimes.)
- int_19h 2y agoIn C# interface members can be implemented explicitly, which means that: 1) they are not visible on the object itself, only on interface-typed references to it, and 2) implementations of methods from multiple interfaces don't need to match since they live in separate namespaces. It's true that you can't access private members (not just fields) on `this` from the mixin interface. But explicit implementations of members mean that only someone explicitly downcasting the object will get access to those members, so accidental access is not an issue.
- DaiPlusPlus 2y ago> How are interfaces with ability to provide default implementations for members (which both C# and Java allow today) not a substitute for mixins? Those default-implementations are only accessible when the object is accessed via that interface; i.e. they aren't accessible as members on the object itself. Furthermore, interfaces (still) only declare (and optionally define) vtable members (i.e. only methods, properties, and events - which are all fundamentally just methods), not fields or any kind of non-static state, whereas IMO mixins should have no limitations and should behave the same as though you copied-and-pasted raw code.
- zozbot234 2y agoRust actually allows one to express "family tree" object inheritance quite cleanly via the generic typestate pattern. It isn't "garbage", it totally has its uses. It is however quite antithetical to modularity: the "inheritance hierarchy" can only really be understood as a unit, and "extensibility" for such a hierarchy is not really well defined. Hence why in practice it mostly gets used in cases where the improved static checking made possible by the "typestate" pattern can be helpful, which has remarkably little to do with "OOP" design as generally understood.
- galbar 2y agoPython has Protocols. They work like Go interfaces
- kragen 2y agoSure, but for the most part people don't use them, because you don't have to; Python method calls are always potentially polymorphic, unlike Golang method calls.
- igouy 2y ago1992 "Interfaces and Specifications for the Smalltalk Collection Classes" https://dl.acm.org/doi/pdf/10.1145/141936.141938 https://dl.acm.org/doi/pdf/10.1145/141936.141938
- kragen 2y agoVery interesting work! It is an attempt to extract the interfaces that were in the minds of the implementors of the Smalltalk-80 system's collection classes, but which couldn't be expressed in the language itself, because it has no interface construct. That's what I meant by "Languages like Smalltalk (...) don't have interfaces at all."
- igouy 2y agoDon't have manifest types and don't have manifest interfaces. Someone has already referenced "Adding Dynamic Interfaces to Smalltalk" [0] and looking back there doesn't seem to be any kind of demonstration that use of interfaces makes software faster to develop or less error prone or... [1] [0] https://www.jot.fm/issues/issue_2002_05/article1/ [1] https://www.cs.utexas.edu/~wcook/papers/OOPSLA89/interfaces.pdf
- kragen 2y agoUnfortunately, in general, there is not much convincing proof that one way of developing software is better than another in such ways.
- igouy 2y agoAnd even if there were: "We are not finders of fact. We are tellers of story. You base the story on the evidence, no? No! We base the evidence on the story. We prove what helps us, and we disprove what hurts us. Whoever tells the best story goes home with the cash-in prizes." (The Good Fight, season 3 episode 2. 30 - 31 minutes. CBS All Access 2019.)