Live data from Hacker News

Inheritance Often Doesn't Make Sense

sicpers.info

221–230 of 255 posts

Re: Inheritance Often Doesn't Make Sense

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

Yes! The thing that ends up breaking in the squares and rectangles examples is mutability. Remember that math things are immutable by default. This thing is a square, and by definition also a rectangle, and since its properties and identity are immutable, that will always be true. However, programming takes those immutable concepts and tends to make them mutable. So now we have a rectangle, and we can change its iden…

> The thing that ends up breaking in the squares and rectangles examples is mutability.

Mutability isn't sufficient.

Breakage requires more than mutability. In dynamic languages, a mutated object can retract its squareness (smalltalk `become`; javascript __proto__ assignment; python object self-mutation). And predicate types (it's a Square iff its sides are the same length) are even graceful.

So I'd rephrase that as "if a specific implementation can mutate in ways that invalidate the laws expected of it, and you can't mutate the laws expected of it to match, your implementation might not match expectations". "Might not", because relaxed and pruned expectations may be locally sufficient.

Re: Inheritance Often Doesn't Make Sense

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

This is far from a silly example; it gets right to the core of the matter. As belorn mentioned, a square is a constrained rectangle, and inheritance by extension cannot represent this relationship.

> square is a constrained rectangle, and inheritance by extension cannot represent this relationship

A hypothetical nice type system, providing a push-out (path independent) lattice of theories/algebras (eg triples of types, operators, and laws) can represent this relationship by extension. It's just adding a law.

That we don't have such a type system available, is I suggest, perhaps the most crippling characteristic of our current tooling. But given the levels of type system research funding over the last decades, it's rather a self-inflicted injury. :/

Re: Inheritance Often Doesn't Make Sense

#223
post #219

Earlier quoted context omitted.

You're confusing inheritance with implementing an interface. I'm not sure there is an example in the real world, because the real world is concerned with function, not taxonomy. It hardly makes sense to say "cordless drill inherits from screw driver"; rather, they both implement the "drives screw" interface. Ontological inheritance really doesn't make any sense at all for modeling systems (sometimes ontologies are us…

I’m not confusing those things. I’m giving an example of an interface, as requested.

[deleted]

Re: Inheritance Often Doesn't Make Sense

#224
The conclusion 'separate out implementation inheritance' rather weakens the claim 'multiple inheritance of implementation isn't useful'. Because then pragmatics can be allowed to dominate.

We do need more powerful vocabulary for composing implementation (eg, to specify object layout spread non-locally in memory). But multiple inheritance can be valuable, and gets a lot of low-quality criticism.

Re: Inheritance Often Doesn't Make Sense

#225
post #199

Earlier quoted context omitted.

I've never seen a C++ codebase without templates in my life.

Template meta-programming is a different usage from template generics. It has a higher compile time cost because it performs computations as a side-effect of compilation.

Which is what the commenter above was trying to say, templates are completely normal, vanilla C++. Also, I cannot think of any codebase that is actively under development and doesn't use some template magic, like at least tuples or variadic perfect forwarding etc... If you look at old codebases you can find them, but template metaprogramming is still very common, mainstream C++.

Re: Inheritance Often Doesn't Make Sense

#226

Earlier quoted context omitted.

There are at least a few ways to define and implement interfaces in C++ without touching inheritance.

Structures of function pointers and, what, string method names? My C++ is rusty, but that's all I can think of. I guess there's a lot of variations on structures of pointers...

Templates and compile-time polymorphism. This is what the STL is based upon. A forward iterator is any type for which the * and ++ operators are defined; you can use it in any template that makes use of just those syntactic forms, but will get a compiler error if you try to instantiate a template with a type that does not support those operators.

Punning on memory layouts, a la PyObject_HEAD or some of the objects in V8. With this approach, you make sure that all related types have the same memory layout for a subset of fields at the beginning of the struct. Then, a reinterpret_cast on a pointer to one member of the type will yield the same values as a different member of the type, and so can be used generically by code that depends only upon those members. (You have to be very careful with this approach, because multiple inheritance and vtables will usually break it, but if you absolutely positively must have zero-overhead runtime polymorphism it's occasionally the best option.)

#include and preprocessor magic to redefine symbols based on preprocessor defines. Used to be the old way to swap out different implementations of a cross-platform interface, but seems to have largely fallen out of favor in the last couple decades.

Linker magic to accomplish the same, where the header file defines a common interface but the linker may link with one of several different object files to implement that interface at link time. This one is still fairly commonly used; Google and Facebook both have their own custom STL & libstdc++ implementations, and this is also commonly used to swap out eg. malloc implementations.

dlopen & dlsym to do this at runtime. Header file defines the interface, dlsym gives you back a function pointer or set thereof for a plugin implementation.

Re: Inheritance Often Doesn't Make Sense

#227
post #21

Earlier quoted context omitted.

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…

But then both are just a kind of polygon, with an arbitrary number of sides of arbitrary length. At which point you really want a variable length list of Sides, each with a length property. Or you want a series of points with relative coordinates, making the sides implicit. Or or or... What I take from it is that there is no one true object model, there is no universally "correct" way of solving the problem. An evolv…

This is a very insightful point. These models and concepts are all human created abstractions.

They contain elements of arbitrariness, describe different levels of detail, focus in on certain aspects or dynamic, leave out other information, and so on.

The skilled software developer must determine how useful and well-suited any particular abstraction is for the actual problem at hand, and judiciously move forward that.

As understanding of the problem domain grows, the abstractions should be updated and discarded to reflect this.

Pragmatism is key -- what does the system actually need to do? Supposed platonic ideals of some conceptual object are often a wild goose chase. Reality is complex. We must embrace it.

Re: Inheritance Often Doesn't Make Sense

#228
post #219

Earlier quoted context omitted.

You're confusing inheritance with implementing an interface. I'm not sure there is an example in the real world, because the real world is concerned with function, not taxonomy. It hardly makes sense to say "cordless drill inherits from screw driver"; rather, they both implement the "drives screw" interface. Ontological inheritance really doesn't make any sense at all for modeling systems (sometimes ontologies are us…

I’m not confusing those things. I’m giving an example of an interface, as requested.

It may have been edited, but at least presently the comment you replied to asks for an example of inheritance.

Re: Inheritance Often Doesn't Make Sense

#229
post #219

Earlier quoted context omitted.

I’m not confusing those things. I’m giving an example of an interface, as requested.

It may have been edited, but at least presently the comment you replied to asks for an example of inheritance.

Oh rats, my mistake. It is harder to come up with s good example of mechanical inheritance. Something like the cassette tape adapter kinda feels like inheritance, in the sense that it can be substituted in for a normal cassette tape but provides its own unique functionality.

Re: Inheritance Often Doesn't Make Sense

#230
post #219

Earlier quoted context omitted.

You're confusing inheritance with implementing an interface. I'm not sure there is an example in the real world, because the real world is concerned with function, not taxonomy. It hardly makes sense to say "cordless drill inherits from screw driver"; rather, they both implement the "drives screw" interface. Ontological inheritance really doesn't make any sense at all for modeling systems (sometimes ontologies are us…

I’m not confusing those things. I’m giving an example of an interface, as requested.

They wanted an example of inheritance. Something like:

You need an office. You could create a new office from scratch, or you could also just put a desk in a room in your house and give it a unique address like "Suite 1". Now it's both a Room and a HomeOffice.

But if your HomeOffice exposes a method BuildWall(), which mutates the office into a collection of two Rooms, then it would stop fitting the definition of a Room after calling that method.

I don't know if there are different tax consequences for one-room vs. multi-room home offices, but that's one area where the distinction could at least conceivably be significant enough to affect whether you'd prefer to build a separate office or inherit the old room, or maybe just rent an existing office from a third party.

Post reply on HN