Live data from Hacker News

When did people favor composition over inheritance?

sicpers.info

201–210 of 218 posts

Re: When did people favor composition over inheritance?

#201
post #43

An important point not mentioned by the article is that of "co-recursion" with inheritance (of implementation). That is: an instance of a subclass calls a method defined on a parent class, which in turn may call a method that's been overridden by the subclass (or even another sub-subclass in the hierarchy) and that one in turn may call another parent method, and so on. It can easily become a pinball of calls around t…

Author here. I wrote “ But even a modestly more recent language like Java has visibility attributes that let a class control what its subtypes can view or change, meaning that any modification in a subclass can be designed before we even know that a subtype is needed.” which covers your situation: if you need to ensure that subtypes use the supertype’s behaviour in limited ways, use the visibility modifiers and `fina…

The fact that Java had to add a whole extra set of keywords to control this indicates that this is a site of complexity. Since it isn't needed for composition, it's a site of unnecessary complexity.

Re: When did people favor composition over inheritance?

#202
post #142

Earlier quoted context omitted.

> In Python you can initialize a class with a constructor that's not even in the inheritance chain No, you can't. Or, at least, if you can, that’s not what you’ve shown. You’ve shown calling the initializer of an unrelated class as a cross-applied method within the initializer. Initializers and constructors are different things. > Oh, bonus point. I've see people creating a second constructor by calling `object.__new…

> Knowing that there are two constructors that exist for normal, non-native, Python classes, and that the basic constructoe Class.__new__, and that the constructor Class() itself calls Class.__new__() and then, if Class.__new__() returns an instance i of Class, also calls Class.__init__(i) before returning i, is pretty basic Python knowledge. I didn't know most of that, and I've performed in a nightclub in Python, ma…

Don't you mean 0Python?

Re: When did people favor composition over inheritance?

#203
post #80

Earlier quoted context omitted.

SOLID is a childish thing, imo. Very undergrad. "Single responsibility" isn't an especially useful yardstick. If you actually need to decompose a complex piece of logic into modules, the place to start is by identifying areas of high cohesion and separating them into loosely coupled functions. Ideally you can match those up to a DDD-style ubiquitous language, so your code will make intuitive sense to people familiar…

Thank you for taking the time to reply, instead of just hitting downvote. I feel like if we argued over a beer we’d probably end up agreeing on a lot of things. But let’s start by disagreeing. :-) > "Does this have one responsibility?" really isn't the right question to ask. It’s a great question to ask. As a senior engineer, the answer might be “no”, but there’s a vast difference between code where the answer is “no…

> I feel like if we argued over a beer we’d probably end up agreeing on a lot of things. But let’s start by disagreeing. :-)

Definitely! :D

Re: SRP, my issue is that it's too subjective. Even for a very simple code snippet like `foo.x = bar.x`, it's not clear whether this covers one responsibility (copying bar's x to foo) or two responsibilities (retrieving bar's x and then setting foo's x). An experienced programmer has enough intuition to understand which of these options is better based on context, but SRP is supposed to be guidance for novices. Maybe I'm asking too much from a one-sentence piece of advice, but maybe splitting up code well requires more than one sentence worth of guidance, and I think SRP boils things down beyond the point of usefulness.

SOLID was invented by Bob Martin, and one of my issues with Martin's style is that he breaks his code into pieces which are far too small. He likes to write methods which are only 2 or 3 lines. Clearly this feels to him like the natural size for a "single responsibility," but to me, he's splitting up highly cohesive code into a profusion of tightly-coupled micro-functions, and I find the result barely legible. This, more than anything, has convinced me that the "one responsibility per function" guideline is just too flexible to be useful on its own.

> I have made many pieces of this system better by evolving a clusterfuck of cohesion into a system that is easy to reason about, maintain and evolve - by apply SOLID principles.

SOLID can describe good code (at least to some degree), but I don't think it's very good at at explaining how to improve code. You're an experienced engineer with good intuition: You see a piece of bad code, you know in your gut what it needs to be changed, and then the final product ends up being SOLID. But if you show the bad code to a junior developer and tell them only, "make it SOLID," I think they'll be lost. They don't have the instincts that tell them whether it's more appropriate to describe a method as having one responsibility or two, or whether they've split things up too much.

> In that sense I could agree open-closed principal is moot, but it’s moot for taking its argument to the logical conclusion.

I'm not sure I follow. My point is that, rather than writing `Foo` in such a way that it's easy to write `FooWithLogging extends Foo`, it should be written in such a way that it's simple to throw away the original `Foo` and write a new version that has logging built in. If you're always extending Foo through inheritance, you end up with a whole string of Foo variants, each piling new features haphazardly upon its parent. Conversely, if you're willing to go back to the drawing board for every new feature, you can evolve a sensible architecture to accommodate any number of features. Of course, if your library has a lot of customers with highly divergent needs, it might be worth building for extensibility, but I don't think that should be the default strategy.

> The most pain has been caused by previous iterations ignoring the open-closed principle.

How so? Injecting new features without adjusting the surrounding architecture to accommodate them naturally? I agree that's a problem, but I feel like extension-by-default also leads to this, since it doesn't give you the opportunity to adjust the original implementation.

Re: When did people favor composition over inheritance?

#204
post #177
post #89

Earlier quoted context omitted.

I use both where choosing what I believe is appropriate for particular case. Frankly I do not give rat's ass about what "People have written extensively". From what I read most of it sounds like spoken by politician: look Jimmy, someone can do a bad thing with it. Well fuckin don't do a bad thing. So much over very simple and primitive thing: John HAS a key vs dog IS an animal. Both are valid and proper. >"you haven'…

> So much over very simple and primitive thing: John HAS a key vs dog IS an animal. Both are valid and proper. I don't think so. "Having" vs "being" are descended from an overly simulationist notion of program design. The fact that John has a key in real life does not suggest that this relationship should be represented by an object John which owns an object Key. I think this kind of ontological approach is behind a…

>"The fact that John has a key in real life does not suggest that this relationship should be represented by an object"

Exactly and that is my point. If you came up with the set of real business entities, their interaction rules and constraints we would have something to discuss and as a curious person and former scientist I would enjoy it. However blanket statements like "one should not use XYZ some abstract community thinks so" to me have near zero value. I do not waste my time on abstract statements taken out of any real life context

>"This is the same rationale used to defend memory-unsafe languages."

Total BS. What one has to do with the other. And even with memory safe languages it is extreme generalization on your side. Come to a company whose life depends on software running their business that had worked for years without problems and was written in say C++ and tell them that they're "holding it wrong" and must "rewrite it in Rust".

>"If we take our craft seriously, we need to be able to discuss the merits and drawbacks of our tools without getting defensive and refusing to engage"

I do take my craft seriously and my craft is to design and implement robust solutions for clients, bring them value and get paid for delivering said value. I do not find arguing abstract concepts disregarding of particular situation having much value.

Re: When did people favor composition over inheritance?

#205
post #175

Earlier quoted context omitted.

- Wording uses “prefer”, not “forbid”. - (java) Least interesting example to rebuke “never”: exceptions, interfaces. - (java) inheritance is used by active and successful projects (e.g. junit5, spring framework). I would argue that success is a pragmatic vindication criteria of a tool/technology.

True; I suppose I could concede the idea that inheritance has its place if we recognize that that place is quite small and out-of-the-way. My problem is that "everything has its place," without any qualifications, is effectively a blank cheque to use inheritance anywhere and then just go, "well that was its place." Interfaces are great; I wouldn't consider them inheritance. Sure, good stuff has been written with inhe…

>"if we recognize that that place is quite small and out-of-the-way"

True Scotsman

Re: When did people favor composition over inheritance?

#206

I am always bemused when i see articles like these. Do people not have an understanding of fundamental Software Engineering principles from OGs like Parnas/Liskov/etc.? The fundamental idea is that of Abstraction which can be defined as the discovery/invention of "higher-level concepts" from more primitive "lower-level concepts" and then reasoning and manipulating at the higher-level. This abstraction is based on str…

>Do people not have an understanding of fundamental Software Engineering principles from OGs like Parnas/Liskov/etc.?

I believe this hints at a major culprit contributing towards the sentiment and use of OO in practice over the years. I'm going to say no people don't. Even if someone goes through education, it won't often require engaging with multiple formative past perspectives at length.. even though there is real value to these musings by comparing and contrasting them altogether first hand.

Re: When did people favor composition over inheritance?

#207
post #163

Earlier 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…

Great points, especially on state management.

I actually can't imagine for the life of me why I'm defending OOP implementation hierarchies here- I guess I got so used to them at work, I've changed my strategy from opposing them to "it's okay as long as you use them sparingly". I have found that argument to do a lot better with my colleagues...

Re: When did people favor composition over inheritance?

#208

Earlier quoted context omitted.

Protected = subclasses can call them. Virtual = subclasses can override them. So basically, any subclass can call the method, and that method may be overridden in any other subclass.

What is the issue with those overrides? They only affect that one path in the hierarchy of inheritance, no? Not a C++ user here, but I imagine it would be catastrophic, if an unrelated (not on path to root superclass) class could override a method and affect unrelated classes/objects.

> They only affect that one path in the hierarchy of inheritance, no?

Not necessarily. If you create a diamond (or a spiderweb :) inheritence pattern, the amount of places the method can be called and overriden grows fast.

Re: When did people favor composition over inheritance?

#209

Gameplay logic inherently leans more towards composition, with a little hint of inheritance. You can have players and monsters, which are all types of "characters" or "units", which is inheritance, but instead of having a separate FlyingPlayer and a separate FlyingMonster, which use the same code for flight, you could have a FlyingComponent, which is composition. I've been going all in on composition and it's amazing…

You can do the very same with inheritance, where `Player` and `Monster` inherit `Flying`

What about walking monsters? Another inheritance branch for those? And other subtrees for other effects? What about making those effects temporary?

Re: When did people favor composition over inheritance?

#210
post #206

I am always bemused when i see articles like these. Do people not have an understanding of fundamental Software Engineering principles from OGs like Parnas/Liskov/etc.? The fundamental idea is that of Abstraction which can be defined as the discovery/invention of "higher-level concepts" from more primitive "lower-level concepts" and then reasoning and manipulating at the higher-level. This abstraction is based on str…

>Do people not have an understanding of fundamental Software Engineering principles from OGs like Parnas/Liskov/etc.? I believe this hints at a major culprit contributing towards the sentiment and use of OO in practice over the years. I'm going to say no people don't. Even if someone goes through education, it won't often require engaging with multiple formative past perspectives at length.. even though there is real…

It is ironical that today when you have a vast body of knowledge literally at your fingertips people seem to have no curiosity nor drive to figure things out for themselves starting from the original sources. Everything seems to be mere parroting and inane opinion pieces with no concept of nuance. People seem to demand a black-and-white (i.e. tell me what is right and wrong) cut-and-dried (i.e. tell me what is settled and decided) answer to all their doubts/queries.

They seem to not understand that nothing in Software Engineering is a definite law but are simply reasonings based on empirical deductions resulting in agreed upon principles/heuristics. Thus meta-principles drive abstractions resulting in concepts which are then expressed via language features. Now, a language feature expresses only those aspects of the fundamental concept that its designer decided as "correct" (i.e. his/her perspective) which is never its full generality eg. Inheritance expression in various languages. So people need to ask themselves "What is the fundamental concept that i am trying to express via this feature?" and slowly work upwards from specific features to general concepts to even more general meta-principles.

Post reply on HN