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.
Why general inheritance is flawed and how to finally fix it
81–90 of 104 posts
Re: Why general inheritance is flawed and how to finally fix it
#82I 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…
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
#83Earlier 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.
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
#84Earlier 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…
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 -> NoneRe: Why general inheritance is flawed and how to finally fix it
#85I 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…
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: FooRe: Why general inheritance is flawed and how to finally fix it
#86Earlier 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.
Re: Why general inheritance is flawed and how to finally fix it
#87How about considering if OOP might be a stupid idea at the first place?
Re: Why general inheritance is flawed and how to finally fix it
#88I 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…
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
#89I'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
#90Fantastic 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…
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.