3 ms·
Inheritance is really just a public interface, a private interface and automatic delegation of those interfaces to the base class. The problems with inheritanc
by lamontcg 3y ago
Inheritance is really just a public interface, a private interface and automatic delegation of those interfaces to the base class.
The problems with inheritance are:
- people shove code in the base class to dedup it without thinking about design
- people add public and protected methods without thinking about interface design
- the names of the base class and the public and protected interfaces are exactly the same thing
The last point is that if you have a FooBase class which is public then you can wind up with a bunch of List<FooBase> containers that are coupled to the base class and external methods that take FooBase parameters along with a bunch of concrete instances which are dependent upon the FooBase class protected interface and code implementation. This creates the brittle base class problem.
If instead you had an IFoo interface and only ever used List<IFoo> instead of FooBase anywhere then you could always define FooBasev2 which implemented IFoo as well and FooBase and FooBasev2 can coexist in your codebase without having to break any external consumers (open-closed principle in practice).
If base classes were only allowed to be used in inheritance and couldn't be parameters, generics, etc then that would force users to create base classes and public interfaces in pairs and would decouple their names and by writing the public interface down as its own thing developers would be more likely to focus on that design.
And really inheritance is just syntax sugar around having a component (the base class) which has automatic delegation of of the public interface and protected interface to it in the inheriting object, with so little typing that it becomes easy to not think about what you're doing -- and while reusing the same name for three different things and creating tight coupling, and you can't dependency inject different baseclasses at runtime. If languages had better terse syntax for delegation then composition would get a lot easier to use like inheritance is (which is something that Go oddly enough gets more-or-less correct, dunno why they didn't mandate piles of boilerplate for delegation like they did for error checking).
- sfn42 3y agoIt's worth mentioning regarding the IFoo example that in a single project you can always just find/replace FooBase with IFoo or even FooBaseV2. I feel like a lot of people blow this up like it's so e huge problem when in reality this is a pretty trivial refactor.
- lamontcg 3y agoNot if you're writing a library/framework that other people use though. If all you do is consume other people's library/frameworks then yeah, nothing really matters, do whatever you want, refactor at will.
- sfn42 3y agoYeah, that's kind of my point. I agree that api design is important if you're publishing a library, even for internal use - that's why I said "in a single project". It seems to me that a lot of people obsess a bit too much about this stuff in places where it doesn't matter.
- dragonwriter 3y ago> If base classes were only allowed to be used in inheritance and couldn't be parameters, generics, etc then that would force users to create base classes and public interfaces in pairs Which, if its a common thing, suggests that there should be syntax for like: interface IFoo from FooBase; That makes an interface from the public members of a class. Or, perhaps even better, type systems should enablr.a distinction between: class ConcreteFoo inherits FooBase; // normal implementation inheritance class ConcreteFoo implements FooBase; // is required to (compiler checked) present the public interface of FooBase, and is type-compatible, but doesn't inherit implementation So concrete classes can also serve as interfaces, and purely abstract classes are identical to interfaces.
- manuel_w 3y ago> If base classes were only allowed to be used in inheritance and couldn't be parameters, generics, etc then that would force users to create base classes and public interfaces in pairs and would decouple their names and by writing the public interface down as its own thing developers would be more likely to focus on that design. I agree and like this principle, however, but what would be the difference between the base class and a mixin class then?
- manuel_w 3y agoTIL that in Python you cannot use a mixin class to provide implementation for an abstract base class that defines the interface. In other words, in the inheritance tree, the class providing the common implementation must sit between the interface class and the concrete classes.