Live data from Hacker News

Inheritance Often Doesn't Make Sense

sicpers.info

61–70 of 255 posts

Re: Inheritance Often Doesn't Make Sense

#61
post #15

> A common counterexample to OO inheritance is the relationship between a square and a rectangle. Geometrically, a square is a specialisation of a rectangle: every square is a rectangle, not every rectangle is a square. Alternatively, you can argue that a rectangle is just a square with the additional freedom to vary the width and height independently. So in C++ syntax you would have: class Square { protected: size_t…

Well, the conceptual view is always first. So in fact a square is a subclass of a rectangle. Implementation comes second, and has to find out how much code sharing is possible.

Re: Inheritance Often Doesn't Make Sense

#62
post #15

> A common counterexample to OO inheritance is the relationship between a square and a rectangle. Geometrically, a square is a specialisation of a rectangle: every square is a rectangle, not every rectangle is a square. Alternatively, you can argue that a rectangle is just a square with the additional freedom to vary the width and height independently. So in C++ syntax you would have: class Square { protected: size_t…

> There in fact is one correct answer but people often get it wrong. You need some serious appreciation of OO to know which. Please enlighten me which one is correct , and I’ll happily argue that the other is in fact correct! (I think you’re going to say Square extending Rectangle is correct lest Rectangle break Square’s invariants, but I’m not certain. What language you’re operating in may influence the matter; for…

If you want to argue about OO you should use Smalltalk. Many other languages use some shortcuts (often for performance reasons) which ignore central concepts of OO (e.g. 'everything is an object').

Re: Inheritance Often Doesn't Make Sense

#63
post #3

Oh, come on. The title submitted to HN is "Inheritance often doesn't make sense"; the actual title of the article is "Why inheritance never made any sense". Are you kidding me? Do we really need, in 2018, another article continuing this particular religious war? Inheritance is just another tool in the software engineer's toolkit. When you need that tool, use it; when you don't, don't. But taking a position where you…

Agree. Tools are only as good and effective as those who use them. At some point we have to be responsible for the decisions we make. And sometimes biz needs change to the point that those decision change from right to wrong. Just me?

I hear the author. Just the same, at 50k ft, it just seems like the same subject on a different topic. That subject is: Peogramming / software engineering is imperfect. And sometimes things break and need to be refactored.

Why should this profession be any different than any other. The quest for The Holy Grail of Perfection is nobel, but we'll never find it.

I'm not suggesting sloppiness and lower standards, but a sense of theory is great but the reality is reality will never be that perfect.

Use the right tool available at the time. When that tool is no longer right and/or effective then replace it. Keep moving.

Re: Inheritance Often Doesn't Make Sense

#64
post #20

> you cannot use a square everywhere you can use a rectangle (for example, you can’t give it a different width and height) Can someone come up with a better example here? Intuitively, I would say, "Yes, if you ask me for any rectangle, and you reject a square, you are wrong." If you say you can use any rectangle to do your thing, you should absolutely be able to also use a square. Why am I not convinced with the give…

> and you can't just will it to have a different width and height and expect it to obey you through some force of nature I think you have let functional programming and immutable data-structures bias your world view. The real world is mutable and the wonder of the digital mutable world is that it is pretty much just will-alone that can set attributes as you describe. It is immutability that is a trendy but artificial…

This is not wrong, but it ignores that in terms of reliable software architectures, it’s very often still better to model change using strictly immutable data types. Often, not always.

As usual the truth is somewhere in the middle, which is why I don’t like the periodically recurring discussions why OO is bad, FP is good or vice versa. I think the article splits up the issue quite nicely, the conclusion I get from it is that the answer to the question whether to use inheritance or not is ‘it depends’.

Re: Inheritance Often Doesn't Make Sense

#65
post #21
post #9

A couple of other comments have argued that "ontological inheritance" and "abstract data type inheritance" are actually the same thing: > This is because Squares are Liskov substitutable for Rectangles... which is because Squares are, platonically, a kind of Rectangle. > If the type system is sound and expressive enough, ontological inheritance ( this thing is a specific variety of that thing) and abstract data type…

I always find that the common example of Rectangles and Squares leads me to a different conclusion. It assume that the best way to go about is to only have a single sideLength method, but from a data structure perspective it seems more obvious that the Squares class substitute instead the validation method by adding constraints that a valid square only exist when both sides are equal. Rectangle class must already hav…

Agreed. In fact I would expect the Square subclass to implement width= and height= so that they each actually set both internal values.

Re: Inheritance Often Doesn't Make Sense

#66
post #53
post #35

Earlier quoted context omitted.

No. Mutation essentially breaks subtyping. The infamous ArrayStoreException in Java is the story of how references (which should be invariant) are treated as covariant and therefore causes runtime exceptions.

Which is only because Java doesn't understand contravariance. In Scala, that problem no longer exists.

No. When references or arrays of references are treated as contravariant, you would have the opposite problem of ArrayReadException. You can now store things into arrays safely but you can no longer extract things from arrays safely.

Re: Inheritance Often Doesn't Make Sense

#67
post #33

Earlier quoted context omitted.

> A common example that is used is when you have a Rectangle.setSize(int width, int height) method. Isn't the fact that we defined a method that changes both sizes at the same time the problem in this case? I mean, if we had two independent methods like `setBase(int)` and `setHeight(int)` this wouldn't be a problem at all (with the assumption, of course, that you accept the fact that the base changes when you change…

The same issue exists for Java Lists. Java lets you pass in subtypes of the type you specified in the List ie it treats them covariantly. This would be correct if the List was immutable but, as you can write to the List, you can blow the type relationship at runtime. In theory a List which you can both read and write should be invariant in the type parameter but this is useless in practice. So Java gives you a useful…

I wasn't talking about generics, I was talking about the `List` interface and its implementations (`ArrayList` and co). Don't they provide a common interface that doesn't leak like the rectangle/square example does?

Also, I posed a question asking if I'm wrong in thinking something, was a downvote really warranted? (Not you specifically, but whoever downvoted)

Re: Inheritance Often Doesn't Make Sense

#68
post #6

Earlier quoted context omitted.

> If you have code that is set up to handle Rectangles, and you give that code a Square, then the code will handle the Square correctly. Hmm...try setting different widths and heights on your square.

Try calculating the diagonal length of your rectangle, where that length is, by definition, 1.414 * width. Alternatively, notice that if your definition of a "rectangle" includes the ability to arbitrarily modify its own width and/or height, then squares are not Liskov substitutable for rectangles and also aren't a kind of rectangle in the "meaning" sense given by definition 1 above. Going by the Liskov criterion, a…

[deleted]

Re: Inheritance Often Doesn't Make Sense

#69
post #66
post #53

Earlier quoted context omitted.

Which is only because Java doesn't understand contravariance. In Scala, that problem no longer exists.

No. When references or arrays of references are treated as contravariant, you would have the opposite problem of ArrayReadException. You can now store things into arrays safely but you can no longer extract things from arrays safely.

Consumers are contravariant in Scala, but producers are covariant.

EDIT: Good reference: https://www.atlassian.com/blog/software-teams/covariance-and...

Re: Inheritance Often Doesn't Make Sense

#70
post #25
post #22

Earlier quoted context omitted.

This is interesting. I find that inheritance as a code reuse tool pushes developers in the direction of taking whatever class they have and tuck some new properties to a subclass. On the other hand, if you realise that a square is a rectangle with the same width and height, why should you bother at all with creating a new class? A new constructor (or an helper function) should be all you need

> On the other hand, if you realise that a square is a rectangle with the same width and height, why should you bother at all with creating a new class? A new constructor (or an helper function) should be all you need What if you have a function that only knows how to operate on squares? Forcing it to accept Rectangles will be unnatural. Of course we can use just a single type Rectangle with two constructors, but inh…

This is a valid point, but now you have two ways of representing a square and you need the coversion functions.

It's better than nothing as you can guarantee that an instance of Square is a square, but you still need to handle squares disguised as Rectangle.

You could throw in dependent types and force rectangles to have different width and height, but that doesn't really help in getting nicer API.

If I had to do something like this in a real program I would take these issues as a sign that I need to step back and re-evaluate my design. I'd look at what I want to use these types for and try to come up with the best approach for that specific case.

Post reply on HN