Hacker News new | ask | show | jobs
by activitypea 1620 days ago
To me, inheritance and polymorphism are two different things. Polymorphism is about different units implementing an interface or equivalent protocol and that rocks. Inheritance is, essentially, dumping a bunch of code into your new class, and most of the time just imposes constraints and breaks API boundaries for no good reason. After studying and doing OOP for about 5 years, I don't see the advantages of inheritance over composition. The only value I see is libraries exposing base classes that enforce behavior on user-written subclasses, stuff like React's Component or Java's HttpServlet. Seems to me we can have polymorphism without subclassing as long as the programming language has a half-decent type system.
2 comments

Yeah; "favor composition over inheritance" remains good advice. "Classical" OO inheritance is brittle and often harmful.
Well, this is one of those "yes and no" situations.

The biggest argument that I hear against OO, is that "someone may misuse or misunderstand it."

I feel that this reflects the tech industry's obsession with hiring armies of relatively inexperienced developers, and then cycling through them, because we don't do what it takes to retain people.

I like composition. I use it often. It is not a "one size fits all" solution to anything; just like OO isn't.

"Reduce state" is another big rallying cry. Good advice, for algorithms, multithreaded service providers, and engines. Not so good, for UI, and, in many cases, device control.

I have spent the last couple of days, working on the login screen for the app I'm developing. It's loaded with state. That can't be avoided, and negotiating the several different states that this -seemingly- innocuous screen can have, is not for the faint of heart, but it needs to be done right, because it's the first screen our users see. It also optionally implements Sign In With Apple, which brings its own baggage. The users' experience must be absolutely frictionless, while also being very secure. The work has involved the server (PHP), the SDK (Swift), and the app, itself (also Swift). I'm not done. I keep uncovering corner cases.

I'm just not a fan of "Don't use X, because X is bad, and you're a bad programmer, if you use X." The tech industry has been dealing with this, since the GOTO wars.

Most of my projects are a hideous chimera of decades-old techniques, mixed with cutting edge stuff.

If someone wants to work on it, then they need to have their stuff together. I'm not going to "dumb it down," but I need to do a lot of documentation (I write about how I document, here: https://littlegreenviper.com/miscellany/leaving-a-legacy/).

Here's an interesting thing that happened to me, some time ago, and I decided to write about it: https://littlegreenviper.com/miscellany/swiftwater/the-curio...

> I feel that this reflects the tech industry's obsession with hiring armies of relatively inexperienced developers, and then cycling through them, because we don't do what it takes to retain people.

That is true (and it won't change, so we need to behave like it won't...), but that is not the only reason.

An inheritance hierarchy in a large program that makes sense today might not make sense in a year or two. Refactoring it is hard. Refactoring a composition-based solution is easier.

Composition-based solutions are also easier to test: inject mocks. It's a lot easier to mock a compositional dependency than it is to mock behavior that's inherited from a parent class.

Given that composition is easier to maintain and test, and that it can achieve the same functionality as inheritance, I've pretty much stopped using inheritance. And I write Java 99% of the time.

I write Apple UIKit apps. I am looking forward to using SwiftUI, which is designed to afford use of Protocol-Oriented Programming, reactive/observer stuff, and a lot of lower-state stuff. I think it would have made the work I've been doing in the last few days, much easier.

But if you use UIKit, then it's fairly important to use classic MVC (not MVVM), as that is what the SDK was specifically designed for. Trying to coerce it into other models just causes a lot of extra pain and complexity.

Also, there are models that have been specifically designed (I won't talk about which), to introduce extra complexity. These are made to allow a design to be "broken up," so that parts can be assigned to different developers.

> and it won't change, so we need to behave like it won't...

I sincerely hope that you're wrong. It's been an unmitigated disaster.

It’s possible (and IMO enjoyable) to write UIKit apps with ComposableArchitecture, a purely value-typed approach. I’ve also mostly used MVVM with UIKit since 2015, and found my apps to be stabler and easier to maintain than standard MVC apps.

In projects I lead I’ve been discouraging inheritance because I’ve found it highly detrimental to maintainability. “Base” classes invite bloat and overgeneralization, especially with inexperienced devs.

Isn't TCA a dependency framework?

I haven't found much joy in MVVM. I haven't found that it provides enough benefits to spend the time switching over.

I am looking forward to SwiftUI. I really hope that the documentation improves, though.

While inheritance can certainly work, especially in terms of UI development, the issue is when you are talking more abstract concepts. At that point, it can become really hard to figure out the right lines for what should be inherited vs composed.

In my experience, poorly composed code is simply easier to understand than code which poorly applies inheritance.

For me, inheritance is best used lightly. The obvious smell is when you end up with methods that don't apply to all the base classes. Or, said another way, when a super class it has a superset of capabilities for a base class.

A good example of this is Java's collections, which, for the most part, are quite good with their inheritance. However, because the base classes have mutable methods, it makes it a pain to deal with unmodifiable collections. Java's mistake is they should have had the default collection be unmodifiable and had sub classes which added mutation capabilities. List and MutableList, for example.

> After studying and doing OOP for about 5 years, I don't see the advantages of inheritance over composition.

I mean, "prefer composition over inheritance" was in the GoF book which is from 1994, and is one of the core OOP books. If you've just been studying OOP for five years, it's likely that you weren't even BORN when this was already industry-level good practice.

Universities in my country are hopelessly stuck in the early 90s :)