Live data from Hacker News

Why general inheritance is flawed and how to finally fix it

minborgsjavapot.blogspot.com

81–90 of 104 posts

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

#81
I got the same feeling reading this article that I got from reading _Design Patterns_: that the author(s) present some useful techniques to deal with the shortcomings of Java, but that most of their recommendations seem like kludgy fixes to problems that are absent or at least much less severe in better-designed languages.

I also note that, while the author does make some useful points about how to program more defensively, especially in the face of unexpected modifications to super/sub classes written by other programmers, one is inevitably beholden to at least a certain extent on the trustworthiness of code that one depends upon. (Even languages like LambdaMoo that start from the assumption that a program consists of code written by multiple mutually-untrusting programmers cannot entirely protect each against malicious subterfuge by the others.) I therefore question the value of the kind of 'hardening' the author recommends, especially when it might have unfortunate consequences on extensibility and testability.

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

#82

I got the same feeling reading this article that I got from reading _Design Patterns_: that the author(s) present some useful techniques to deal with the shortcomings of Java, but that most of their recommendations seem like kludgy fixes to problems that are absent or at least much less severe in better-designed languages. I also note that, while the author does make some useful points about how to program more defen…

On the "how to program more defensively" point, the author techniques are not meant to protect against malice (you are right that in such case of malice there is nothing that can be done), but instead to protect against foot guns, where innocent and reasonable changes in a module internals might unknowingly break another module.

I believe the author's arguments are quite valid, inheritance breaks the concept of a "black box" in Object Oriented Design. Once you inherit from a class, all that class internals become an "unadvertised signature", nothing is a black box that can be transparently changed anymore, any internal change may break a subclass.

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

#83
post #42

Earlier quoted context omitted.

COM solves this with delegation, where objects can only implement the methods that they care about and delegate everything else to the aggregated type, which provided the full interface. However, depending on which stack one is using (VB 6, .NET, MFC, ATL, WRL, WinRT), the amount of boilerplate to deal with the runtime differs.

I wish more languages (in fact, any popular languages!) had convenient syntax for this.

Dynamic languages have it, via "doesNotUnderstand" and similar.

Kotlin also provides a way similar to those COM variants,

https://kotlinlang.org/docs/delegation.html#overriding-a-mem...

Best support is probably MOP in Common Lisp, I guess.

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

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

Standard ML and OCaml have both sum types (like in Rust) and exceptions. I feel like both have their value, and both are important. A nice thing is that you can match on exceptions:

    match number_of_lines_of_a_file() with
    | x -> x
    [ exception File_not_found -> 0
This makes it really easy to create alternative versions of functions, using exceptions or option types:

    match number_of_lines_of_a_file_opt() with
    | Some x -> x
    | None -> raise File_not_found

    match number_of_lines_of_a_file_exc() with
    | x -> Some x
    | exception File_not_found -> None

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

#85

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. s…

In Python you could do something like:

  class Base:
     def func(self):
         print("In Base.func:", self.name)
  
  class Child:
     def __init__(self, name):
         self.name = name
     func = Base.func
  
  c = Child("Foo")
  c.func() #=> In Base.func: Foo

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

#86
post #83

Earlier quoted context omitted.

I wish more languages (in fact, any popular languages!) had convenient syntax for this.

Dynamic languages have it, via "doesNotUnderstand" and similar. Kotlin also provides a way similar to those COM variants, https://kotlinlang.org/docs/delegation.html#overriding-a-mem... Best support is probably MOP in Common Lisp, I guess.

The Kotlin version is pretty much what I had in mind, that's pretty nice.

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

#88

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. s…

C++ can do something something like this (at compile time) in its -> operator (ancient feature, long before C++98 was standardized).

   obj->foo()
will expand into enough -> dereferences until a foo is found. For instance suppose the object returned by obj's operator ->() function doesn't have a foo member, but itself overloads ->. Then that overload will be used, and so on.

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

#89
The real world rarely sticks with nice hierarchies. Variations of set theory is more powerful, but would generally require merging RDBMS with IDE's, which does deserve more R&D. Using code to manage complex sets is limiting; query languages do it smoother because that's what they were intended for.

I've experimented myself with "table oriented programming", but don't have time to explore all the leads I uncover and rework the problem areas. Maybe when I retire?

For example, modern CRUD stacks are really just "event handling databases" done poorly. An RDBMS would be better at managing the gazillion event snippets, if it could "talk to" the compiler properly.

The "do everything in code" mantra of the web era is a mistake. Databases are better at managing complex relationships and masses of field/UI attributes, code better at non-collection-oriented algorithms. We should use the right tool for the job. "Data annotations" in Java and C# look like JCL's mutant stepdaughter. If that's the pinnacle of CRUD, then slap me silly.

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

#90
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 or traits are better ways to represent polymorphic behaviors. We've known this for over a decade now.

The trend is in the opposite direction.

TypeScript enables JavaScript programmers to benefit from static typing, and is seeing widespread use. Python now has type-hints.

Post reply on HN