Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I mean, it's not that hard to understand, why composition is to be preferred, when you could easily just use composition instead of inheritance. It's just that people, who don't want to think have been cargo-culting inheritance ever since they first heard about it, as they don't think much further than the first reuse of a method through inheritance.


No, it's not a complete replacement for inheritance.


Nor did I claim so.


Composition folks can get very dogmatic.

I have some data types (structs or objects), that I want to serialize, persist, and that they have some common attributes of behaviors.

In swift I can have each object to conform to Hashable, Identifiable, Codabele, etc etc... and keep repeating the same stuff over and over, or just create a base DataObject, and have the specific data object inherit it and just .

In swift you can do it by both protocols, (and extensions of them), but after a while they start looking exactly like object inheritance, and nothing like commposition.

Composition was preferred when many other languages didn't support object oriented out the gate (think Ada, Lua, etc), and tooling (IDEs) were primitive, but almost all modern languages do support it, and the tooling in insanely great.

Composition is great when you have behaviour that can be widely different, depending on runtime conditions. But, when you keep repeating yourself over and over by adopting the same protocols, perhaps you need some inheritance.

The one negative of inheretance is that when you change some behaviour of a parent class, you need to do more refactoring as there could be other classes that depend on it. But, again, with today's IDEs and tooling, that is a lot easier.

TLDR: Composition was preferred in a world where the languages didn't suport propper object inheretance out of the gate, and tooling and IDEs were still rudemmentary.


> In swift I can have each object to conform to Hashable, Identifiable, Codabele, etc etc... and keep repeating the same stuff over and over, or just create a base DataObject, and have the specific data object inherit it and just .

But then if you need a DataObject with an extra field, suddenly you need to re-implement serialization and deserialization. This only saves time across classes with exactly the same fields.

I'd argue that the proper tool for recursively implementing behaviours like `Eq`, `Hashable`, or `(De)Serialize` are decorator macros, e.g. Java annotations, Rust's `derive`, or Swift's attached macros.


Yes, all behaviors should be implemented like definitions in category theory: X behaves like a Y over the category of Zs, and you have to recursively unpack the definition of Y and Z through about 4-5 more layers before you have a concrete implementation.


I'll be honest here. I don't know if any comment on this thread is a joke.

There are valid reasons to want each one of the things described, and I really need to add type reflexivity to the set here. Looks like horizontal traits are a completely unsolved problem, because every type of program seems to favor a different implementation of it.


    > The one negative of inheretance is that when you change some behaviour of a parent class, you need to do more refactoring as there could be other classes that depend on it. But, again, with today's IDEs and tooling, that is a lot easier.
It is widely known as the "unstable base class" problem.

Another one is, that there are cases, where hierarchies simply don't work well. Platypus cases.

Another one is, that inheritance hides where stuff is actually implemented and it can be tedious to find out when unfamiliar with the code. It is very implicit in nature.

    > TLDR: Composition was preferred in a world where the languages didn't suport propper object inheretance out of the gate, and tooling and IDEs were still rudemmentary.
I think this is rather a rewriting of history to fit your narrative.

Fact is, that at least one very modern language, that is gaining in popularity, doesn't have any inheritance, and seems to do just fine without it.

Many people still go about "solving" problems by making every noun a class, which is, frankly, a ridiculous methodology of not wanting to think much. This kind of has been addressed by Casey Muratori, who formulated it approximately like this: Making 1-to-1 mappings of things/hierarchies to hierarchies of classes/objects in the code. (https://inv.nadeko.net/watch?v=wo84LFzx5nI) This kind of representing things in the code has the programmer frequently adjusting the code and adding more specializations to it.

One silly example of this is the ever popular but terrible example of making "Car" a class and then subclassing that with various types of cars and then those by brands of cars etc. New brand of car appears on the market? Need to touch the code. New type of car? Need to touch the code. Something about regulations about what every car needs to have changes? Need to touch the code. This is exactly how it shouldn't be. Instead, one should be thinking of underlying concepts and how they could be represented so that they can either already deal with changes, or can be configured from configuration files and do not depend on the programmer adding yet another class.

Composition over inheritance is actually something, that people realized after the widespread over-use of inheritance, not the other way around, and not because of language deficiencies either. The problems with inheritance are not merely previously bad IDE or editor support. The problems are, that in some cases it is bad design.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: