Live data from Hacker News

Why general inheritance is flawed and how to finally fix it

minborgsjavapot.blogspot.com

71–80 of 104 posts

Re: Why general inheritance is flawed and how to finally fix it

#71

I (happily) write a lot of OOP code, "inheritance is bad, use composition" is such a trite and unhelpful dogma that gets in the way of any actual discussion about where inheritance is useful. IMO, the case where inheritance makes the most sense is when you have a set of objects polymorphically answering some question, usually with a simple answer. class Subset class Whole which is used as such: subset = Subset::Whole…

that approach gives me headaches to think about. Why not just have polymorphic functions?

    fn subset(superset, start, end){
        // superset is type inferred as long as it supports the [] operator
        // logic to collect superset[start] to superset[end] into an array and return it
    }
with uniform function call syntax:

    [1,2,3,4,5,6].subset(1,4) == [2,3,4,5]
If you really want to reuse a subset range, you can use lambdas/closures, or in this case a simple wrapper

    // in some code
    fn subset1to4(superset){
        return subset(superset,1,4)
    }
    array.subset1to4()
    anotherArray.subset1to4()

Re: Why general inheritance is flawed and how to finally fix it

#72

Earlier quoted context omitted.

Arguably, subtyping in am OO language should either be signatures/interfaces only, or you should go full blown multiple inheritance for everything, as with the Fortress language.

Golang ide struggle with answering what implements this interface. The compiler obviously handles that fine It makes it difficult to jump into an unfamiliar project Assuming that’s what you mean by signature/ interfaces

But this is an issue with tooling.

IntelliJ with Java/Kotlin does a great job here.

Re: Why general inheritance is flawed and how to finally fix it

#73

I (happily) write a lot of OOP code, "inheritance is bad, use composition" is such a trite and unhelpful dogma that gets in the way of any actual discussion about where inheritance is useful. IMO, the case where inheritance makes the most sense is when you have a set of objects polymorphically answering some question, usually with a simple answer. class Subset class Whole which is used as such: subset = Subset::Whole…

In a language where most errors will be runtime errors (Ruby), the inheritace problem described in the article is much less of a problem.

In such a language (e.g. Ruby), you will need test suites where languages with (strong) types use the type system to prove some level of correctness.

I used to be a fan of dyn typed langs (Ruby), but I've changed, I prefer strongly typed langs now for anything more than quick throw away scripts.

Re: Why general inheritance is flawed and how to finally fix it

#74

Earlier quoted context omitted.

Arguably, subtyping in am OO language should either be signatures/interfaces only, or you should go full blown multiple inheritance for everything, as with the Fortress language.

Golang ide struggle with answering what implements this interface. The compiler obviously handles that fine It makes it difficult to jump into an unfamiliar project Assuming that’s what you mean by signature/ interfaces

C++ is much more complicated than go in that regards and my IDE generally does not have trouble with it

Re: Why general inheritance is flawed and how to finally fix it

#75

I think that composition is absolutely better than inheritance except for one thing: boilerplate. The issue is that boilerplate is kind of important. You don't want to litter your code with "f150.ford.car.vehicle.object.move(50, 50)". You can and should re-implement "move" so that you only have to call "f150.move(50, 50)", but that still requires boilerplate, just in the "F150" class. Often you have class containing…

I'd like languages to have some kind of "delegate" functionality, where you can just delegate names to point to nested names without screwing around with ownership - it would just act like a symlink. The scope of that action is limited and clear (and easy for your IDE to understand), and it's explicit that the subclass is still the "owner" of that property, which makes the whole thing a lot easier to navigate.

E.g. something like:

    class MyClass:
        def __init__(self, member_class):
            self.member_class = member_class

        # Delegate one member
        delegate move member_class.position.move

        # Delegate all members
        delegate * subclass.position.*             

Then:

    a.move == a.member_class.position.move
etc.

Re: Why general inheritance is flawed and how to finally fix it

#76
post #66

Earlier quoted context omitted.

This question determines if you need to be DRY or not: "If [some fact] in the code base needs to change, how many places would we have to change it in?" If the answer is > 1, you have a very good DRY case. Otherwise, when [some fact] changes, it will probably not be changed in one of the places, and the system will be broken. This often coincides with having an "elegant codebase", but that's not the most important pa…

A younger self used to be very strict about DRY. For a living codebase, nowadays my general rule of thumb is to consciusly duplicate code until it covers 3 different cases, and only then refactor (unless the DRY way is as fast and obvious). It takes more than that to yield spaghetti and a lot of time is saved on premature generalization. Plus the generalization is often way more straightforward once the explicit case…

https://en.wikipedia.org/wiki/Rule_of_three_(computer_progra...

I follow this too for "style" refactorings.

Re: Why general inheritance is flawed and how to finally fix it

#77
post #68

Earlier quoted context omitted.

Interfaces would work fine here as well.

As someone who is greatly in favor of composition over inheritance, I don't agree - or at least my experiences don't point that way. Both Rust and Go have had medium sized warts and/or boilerplate around errors, especially if you need control flow to depend on the error. In Python I've never felt that way. Not sure I can put my finger on it, because any trivial example would be fine in either paradigm. I think it has…

flow control is always impacted by errors. rust and go just don't hide that on you with a giant 'go to random location in the stack' capability.

Re: Why general inheritance is flawed and how to finally fix it

#78
post #69

Or you could learn to use it properly. Make no mistake, designing classes to support inheritance is much harder than just declaring everything final, and in many scenarios there is no good reason to do so

I _hate_ smart asses that do "everything final by default". It all fun and giggles until I can't mock some stupid class in some stupid library that I have no choice but to use just because someone is high on "inheritance is bad" hype. Instead of normal mocking/stubbing I now have to use stuff like PowerMock which does byte code hacking just so I can have a test. How about you stop making decisions for me and let _me_…

  > I can't mock some stupid class in some stupid library that I have no choice but to use just because someone is high on "inheritance is bad" hype.
yea, at the very least, classes public members should be more like interfaces, that way mocking can be done easily in test mode, then in prod build lots of optimizations could "dissolve" the interface and be statically dispatched etc... hmmm....

Re: Why general inheritance is flawed and how to finally fix it

#79
post #27

The term "general inheritance" was not familiar to me as "inheritance across package structures". However, my OOP design intuition feels pretty good about that idea. This quickly devolves into the inheritance vs. composition argument which isn't where I thought the Author wanted to go (but then sort of ended up going there). I agree with other commenters that it's an overstated idea. Inheritance is ridiculously usefu…

> Inheritance is ridiculously useful in the right design structure

I’ve made very little use of inheritance since I turned my back on C++/Java a decade and change ago. Can you give some examples where you feel inheritance wins out over composition?

Re: Why general inheritance is flawed and how to finally fix it

#80
post #39

Fantastic article! Object oriented programming gets a horrible wrap on the basis of inheritance alone, and it's no wonder. Outside of limited domains, such as GUI programming, object inheritance makes little sense. Computer science students are right to question their introductory classes on inheritance when they teach contrived examples of dogs barking and cats meowing as an example of Mammal.makeSound() inheritance…

Duck typing is terrible if you want understandable code. The world has largely moved away from this for good reason.
Post reply on HN