Live data from Hacker News

Inheritance Often Doesn't Make Sense

sicpers.info

21–30 of 255 posts

Re: Inheritance Often Doesn't Make Sense

#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 have a validation method that check that each side is greater than zero, so it seem like the obvious place to define a square. Any additional methods or properties like sideLength would just be added convenience and optimization to access the width and height at the same time, but which is not required for anyone substituting one for the other.

Re: Inheritance Often Doesn't Make Sense

#22
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…

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

Re: Inheritance Often Doesn't Make Sense

#23
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…

In Scala, partial function is a subtype of function, even though it would seem like the opposite should be true, conceptually.

Thanks for the example. Yeah this is another case where people have trouble understanding subtyping relation and which type should be the subtype of which.

And I agree with you that the opposite should be true conceptually, because if you ask yourself, "if a partial function is being demanded, can you use a function instead?" you might answer yes.

Alternatively, think of a partial function conceptually as a function that returns an option type, i.e. in Haskell syntax

    type Function a b = a -> b
    type PartialFunction a b = a -> Maybe b
and with the obvious addition that "b" is a subtype of "Maybe b", then we again conclude that function should be a subtype of partial function.

Re: Inheritance Often Doesn't Make Sense

#24
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.

Many rectangle APIs, even in OO languages, are immutable, so setting width and length isn’t allowed anyways, all you can do is operate on it to get a new one. I’ve rarely seen a square subtyped as a rectangle, let alone a mutable one. But I guess it’s possible if the mutable and immutable APIs are divided, so that squares are rectangles in its immutable sense but not in its mutable one.

This also pops up in modeling sets. You can define an immutable set by its explicit list of members (intrinsic) or by function that tests membership (extrinsic). If you want to have only one unified type Set that permits both methods of construction, it has to be invariant with respect to the type of its members. This is because the intrinsic approach is covariant (just as a list is) but the extrinsic approach is contravariant (just as a function is in its inputs).

I wish I had a really clear example of this, but it escapes me right now.

Re: Inheritance Often Doesn't Make Sense

#25
post #22
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…

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 inherently that's throwing information away about certain conditions we know to be true.

Even in functional programs when we don't have inheritance, we still sometimes need conversion functions between related types and whether or not these use option types illustrates essentially the same idea:

    data Rectangle = Rectangle Int Int
    
    data Square = Square Int
    
    recToSq :: Rectangle -> Maybe Square -- may not succeed; like downcasting
    
    sqToRec :: Square -> Rectangle -- always succeeds; like upcasting
Indeed, this is exactly what the "coercion semantics" in subtyping means: whenever S is a subtype of T, we can generate a total function from S to T. I believe this is also called "inheritance as implicit coercion" in https://www.sciencedirect.com/science/article/pii/0890540191... Quoting from the abstract:

> We present a method for providing semantic interpretations for languages with a type system featuring inheritance polymorphism. […] Our goal is to interpret inheritances in Fun via coercion functions which are definable in the target of the translation.

Re: Inheritance Often Doesn't Make Sense

#26
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…

[deleted]

Re: Inheritance Often Doesn't Make Sense

#27
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…

> But taking a position where you say it's never the right tool or, conversely, always the right tool makes you sound ignorant and inexperienced.

Neither of those positions is advocated by the article, so who exactly are you talking about?

In fact, you seem to have assumed that "make sense" in the title referred to the issue of whether or not to use inheritance, whereas in fact the article is concerned with the customary conceptual understanding of inheritance within software engineering, and whether this understanding "makes sense".

This is an easy enough mistake to make simply from reading the title, but one that should have been cleared up in a matter of seconds once you started reading the article body, which I presume you did, rather than immediately rushing to the comment section?

Re: Inheritance Often Doesn't Make Sense

#28
post #23

Earlier quoted context omitted.

In Scala, partial function is a subtype of function, even though it would seem like the opposite should be true, conceptually.

Thanks for the example. Yeah this is another case where people have trouble understanding subtyping relation and which type should be the subtype of which. And I agree with you that the opposite should be true conceptually, because if you ask yourself, "if a partial function is being demanded, can you use a function instead?" you might answer yes. Alternatively, think of a partial function conceptually as a function…

For sure. And since all functions can throw exceptions, a partial function is just a function that just happens to throw a lot of them :)

Re: Inheritance Often Doesn't Make Sense

#29
I don't understand why some functional programmers have so much difficulty with the concept of inheritance. Discriminated Unions and pattern matching is just inheritance and virtual dispatch turned inside out. Yet no one is naval gazing about whether their algebraic datatypes are 'ontological' or not.

I also really wish people wouldn't try and dismiss concepts they're ignorant of:

because multiple inheritance is incompatible with the goal of implementation inheritance due to the diamond problem

I have no idea what that sentence is supposed to mean. It doesn't make sense even given their own definition of implementation inheritance.

Re: Inheritance Often Doesn't Make Sense

#30
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 layer on top of this reality.

Post reply on HN