Live data from Hacker News

Liskov Substitution: The real meaning of inheritance

cekrem.github.io

21–30 of 92 posts

Re: Liskov Substitution: The real meaning of inheritance

#21
post #4

Do yourself a favor and wear yourself off all this SOLID, Uncle Bob, Object Oriented, Clean Code crap. Don't ever use inheritance. Instead of things inheriting from other things, flip the relationship and make things HAVE other things. This is called composition and it has all the positives of inheritance but none of the negatives. Example: imagine you have a school system where there are student users and there are…

Never using inheritance is pushing the dogma to the other extreme imo. The whole prefer composition over inheritance is meant to help people avoid the typical OO over use of inheritance. It doesn't mean Is-A relation doesn't/shouldn't exist. It just means when there is data, prefer using composition to give access to that data. There will be times when you want to represent Is-A relationship - especially when you wan…

I see no need for inheritance there, that can and should be done using interfaces

eg in the contrived example I gave, any of all three of the User, Student and Employee can implement the interface (and if needed Student could simply delegate to its internal User while Employee could "override" by providing its own, different implementation)

Re: Liskov Substitution: The real meaning of inheritance

#22
post #4

Do yourself a favor and wear yourself off all this SOLID, Uncle Bob, Object Oriented, Clean Code crap. Don't ever use inheritance. Instead of things inheriting from other things, flip the relationship and make things HAVE other things. This is called composition and it has all the positives of inheritance but none of the negatives. Example: imagine you have a school system where there are student users and there are…

Just because you see OO languages starting to favor composition over inheritance does not mean inheritance has no place, and indeed, interfaces as a form of composition have existed in many bog-standard OO languages for decades. Your example dosn't compute, at least in most languages, because derived objects would not have the same shape as one another, only the shape of the base class. I.e. functions expecting a Use…

> The alternative is that you wind up implementing the same 5-10 interfaces repeatedly for every different object you create.

if both Student and Employee need to implement those interfaces, it's probably User that should have and implement them, not Student and Employee (and if they truly do need to have an implement them, they can simply delegate to their internal User = "no override" or provide a unique implementation = "override") (let alone that unless I'm misremembering in Kotlin interfaces can have default implementations)

Re: Liskov Substitution: The real meaning of inheritance

#23
post #4

Do yourself a favor and wear yourself off all this SOLID, Uncle Bob, Object Oriented, Clean Code crap. Don't ever use inheritance. Instead of things inheriting from other things, flip the relationship and make things HAVE other things. This is called composition and it has all the positives of inheritance but none of the negatives. Example: imagine you have a school system where there are student users and there are…

Never using inheritance is pushing the dogma to the other extreme imo. The whole prefer composition over inheritance is meant to help people avoid the typical OO over use of inheritance. It doesn't mean Is-A relation doesn't/shouldn't exist. It just means when there is data, prefer using composition to give access to that data. There will be times when you want to represent Is-A relationship - especially when you wan…

Never is a good starting point as a guide but of course there are cases where is-a makes sense too.

Composition generally is not good enough to model all cases without resulting to some AOP or meta programming also, but in that case the is-a or a base class would arguably be the simpler approach, at least it can be reasoned about and debugged, as opposed to some AOP/Meta spaghetti that can only probably be understood from docs

Re: Liskov Substitution: The real meaning of inheritance

#24
post #16
post #4

Do yourself a favor and wear yourself off all this SOLID, Uncle Bob, Object Oriented, Clean Code crap. Don't ever use inheritance. Instead of things inheriting from other things, flip the relationship and make things HAVE other things. This is called composition and it has all the positives of inheritance but none of the negatives. Example: imagine you have a school system where there are student users and there are…

> Don't ever use inheritance. Instead of things inheriting from other things, flip the relationship and make things HAVE other things. This is called composition and it has all the positives of inheritance but none of the negatives. Bah. There are completely legitimate uses of inheritance where it's a really great fit. I think you'll find that being dogmatic about avoiding a programming pattern will eventually get yo…

I happily admit it's more than possible to come up with examples that make inheritance shine. After all, that's what the authors of these books and articles do.

But most of them put the cart before the horse (deliberately design a "problem" that inheritance "solves") and don't seriously evaluate pros and cons or even consider alternatives.

Even then, some of the examples might be legitimate, and what you're referring to might be a case of one. (though I doubt there's no equally elegant and succinct way to do it without inheritance)

But none of that changes the fact that inheritance absolutely shouldn't be the default goto solution for modeling any domain it has become (and we are taught to understand it as)

or that it's exceedingly uncommon to come across situations like yours where you have 500+ shared cases of behavior and you only want to "override" 5

or that inheritance is overwhelmingly used NOT for such niche edge cases but as a default tool to model even the most trivial relationships, with zero justification or consideration

Re: Liskov Substitution: The real meaning of inheritance

#26
post #16
post #4

Do yourself a favor and wear yourself off all this SOLID, Uncle Bob, Object Oriented, Clean Code crap. Don't ever use inheritance. Instead of things inheriting from other things, flip the relationship and make things HAVE other things. This is called composition and it has all the positives of inheritance but none of the negatives. Example: imagine you have a school system where there are student users and there are…

> Don't ever use inheritance. Instead of things inheriting from other things, flip the relationship and make things HAVE other things. This is called composition and it has all the positives of inheritance but none of the negatives. Bah. There are completely legitimate uses of inheritance where it's a really great fit. I think you'll find that being dogmatic about avoiding a programming pattern will eventually get yo…

If you can use functions in the same way objects are used, there’s no need for visitor objects.

There’s a reason why everything is a Lisp. All of the patterns are obvious with its primitives, while higher level primitives like classes, interfaces hide that there’s data and there’s behavior/effects.

Re: Liskov Substitution: The real meaning of inheritance

#27

Earlier quoted context omitted.

Inheritance has no place in production codebases—unless there is strict discipline, enforced by tooling, ensuring calls only go in one direction. This Liskov stuff has zero bearing.

Respectfully, I think you're throwing the baby out with the bathwater. I read your story, and I can certainly empathize. But just because someone has made a tangled web using inheritance doesn't mean inheritance itself is to blame. Show me someone doing something stupid with inheritance and I can demonstrate the same stupidity with composition. I mean, base classes should not be operating on derived class objects out…

I believe the problem is structural to all traditional class-based inheritance models.

The sort of situation I described is almost impossible with trait/typeclass-based polymorphism. You have to go very far out of the idiom with a weird mix of required and provided methods to achieve it, and I have never seen anyone do this in practice. The idiomatic way is for whatever consumes the trait to pass in a context type. There is a clear separation between the call-forward and the callback interfaces. In Rust, & and &mut mean that there's an upper limit to how tangled the interface can get.

I'm fine with inheritance if there's rigorous enforcement of one-directional calls in place (which makes it roughly equivalent to trait-based composition). The Liskov stuff is a terrible distraction from this far more serious issue. Does anyone do this?

> You shouldn't have to duplicate code or nest structures to attain those ergonomics.

What's wrong with nesting structures? I like nesting structures.

Re: Liskov Substitution: The real meaning of inheritance

#28
post #4

Do yourself a favor and wear yourself off all this SOLID, Uncle Bob, Object Oriented, Clean Code crap. Don't ever use inheritance. Instead of things inheriting from other things, flip the relationship and make things HAVE other things. This is called composition and it has all the positives of inheritance but none of the negatives. Example: imagine you have a school system where there are student users and there are…

I will agree that the problem that class hierarchies attempt to solve is a problem one usually does not really have, but in your example you have not solved it at all. It matches a relational database well, but once you have a just a user reference, you can not narrow it down to an employee without out of band information. If a user should be just one type that can be multiple things at once, you can give them a set…

I agree that there are better ways to model roles and FGA

the point of the example wasn't to be an idiomatic solution to that problem, but to illustrate the pointlessness of inheritance in general, and User Student Employee was the first thing that came to mind that was more "real" than the usual Animal examples

in any case, as for only having a User reference, you don't ever have only a User reference - overwhelmingly you would usually load a Student or Employee,

and each of them would have those attributes on them that characterize each of them respectively (and those attributes would not be shared - if they were, such shared attributes would go on the User object)

only those functions that truly are operating only on User would you send in each of their User objects

the problem with what you're advocating is you end up with functions like this

    fun doSomething(user: User) { if (user is Student) { do this } else { do that } }
which is insane

Re: Liskov Substitution: The real meaning of inheritance

#29

If I remember correctly, Liskov didn't talk about inheritance but subtyping in a more general way. Java, C++ and other, especially statically typed, compiled languages often use inheritance to model subtyping but Liskov/Wing weren't making any statements about inheritance specifically.

>subtyping in a more general way

This is correct. I read her paper closely. One example I give is how SICP provides two implementations for complex numbers[1], the rectangular for and polar form.

    (make-rectangular (real-part z) (imag-part z))
and

    (make-polar (magnitude z) (angle z))
then on page 138 provides this interface that both satisfy

    (define (real-part obj) (operate 'real-part obj))
        (define (imag-part obj) (operate 'imag-part obj))
        (define (magnitude obj) (operate 'magnitude obj))
        (define (angle obj) (operate 'angle obj))


1 https://mitp-content-server.mit.edu/books/content/sectbyfn/b...

Re: Liskov Substitution: The real meaning of inheritance

#30
Like most articles on "Inheritance" this is clueless about providing any "real meaning/understanding". People always take the soundbites (eg. Uncle Bob SOLID) provided as a mnemonic as being the end-all, don't fully understand the nuances and then usually arrive at a wrong conclusion.

LSP (https://en.wikipedia.org/wiki/Liskov_substitution_principle) has to do with behavioural subtyping guaranteeing semantic interoperability between types in a hierarchy. It involves not just the syntax of function signatures but their semantic meaning involving Variance/Invariance/Covariance/Contravariance and their guarantees using an extension to Hoare Logic i.e. Preconditions/Postconditions/Invariants (derived from Meyer's DbC). Thus without enforcing the latter (which is generally done via documentation since there is no syntax for expressing pre/post/inv directly in most languages) the former is incomplete and thus the complete contract is easily missed/forgotten leading to the mistaken belief "Inheritance is bad". The LSP wikipedia page links to all the concepts, the original papers and more for further clarification.

See also Bertrand Meyer's Using Inheritance Well from his book Object Oriented Software Construction, second edition book - https://archive.eiffel.com/doc/manuals/technology/oosc/inher...

Finally see Barbara Liskov's own book (with John Guttag) Program Development in Java: Abstraction, Specification, and Object-Oriented Design for a "correct approach" to OOP. Note that Java is just used as a example language while the principles are language independent.

Post reply on HN