Jimmy Koppel Profile picture
Mar 8, 2023 23 tweets 5 min read Read on X
"The Flaws of Inheritance" by @CodeAesthetic1 is beautiful, as always.

Problem though, is that none of the things discussed in the video have anything to do with inheritance

Time for a 🧵 on the most mind-bending construction in mainstream programming languages
@CodeAesthetic1 Some context: I was talking to Norman Ramsey a few months ago about his new book. We started talking about objects, and he told me he barely covers them. Why? "Objects are not an undergrad topic"
Inheritance is probably the hardest part of the theory of objects.

If I say "X doesn't understand inheritance," read it in the same tone as "X doesn't understand quantum Chu algebras."

Here's how the late William Cook defined it Image
Back to CodeAesthetic.

He says that the greatest downfall of inheritance is that, if you want to add a new variant that implements some methods but not others, you need to change the base class and many consumers.

That has nothing to do with inheritance. Image
Rather, that's a problem of putting too much stuff in an interface

Haskell doesn't have classes, but you can have this problem by putting too much stuff in a typeclass

#JuliaLang really doesn't have classes, but you can write code assuming everything which supports + also has *
Funny enough, the video's example of composition actually isn't

Composition requires that an object have another object as a field, but the "composed" version here just takes an image as a param. It's providing a helper function, not extending an image with new functionality Image
Something that throws people is that classes in mainstream programming languages actually combine 8 different concepts into one.

It's important to distinguish these concepts, as some of them come with opposite advice. We're told to avoid instanceof for objects, but if your objects actually encode a sum type, then it's required.
This conflation kills the video's attempted classifaciton.

Both entries in the Inheritance row are wrong. Image
First, trying to compare "parent classes" with "interfaces" does not typecheck.

That's like saying "Use an Aeron instead of a chair."
Interfaces are a record mapping method names to types, together with properties they should satisfy

Classes are implementations

It works this way in type theory, but it also works this way in major languages as they're actually used, where people use IWidget instead of Widget
If you only refer to values through their interfaces, then this becomes non-distinguishing.

You can inherit from a class all you want and wind up with a new implementation of the same interface. You can toss in any combination of new interfaces you want.
The "extending part" is also wrong.

What? Isn't that what inheritance is all about.

Nope. That's subtyping.
In fact, usual presentations of composition also are just extending.

The prototypical example of composition is a hash table that also counts the number of times put() was called. Same operations, plus a getCount. Composition can (should?) be extending as well!
Similarly, you extend an interface just by throwing on a couple more methods. No inheritance in sight. This is also present in languages that don't support objects, like Haskell and its typeclasses.
So, what is inheritance?

That's a 90-minute lesson I give to select alumni of my course ( mirdin.com/the-advanced-s… ), but here's the short version:

Inheritance is creating a new implementation from old

For it to be more than subtyping, you must override existing methods!
Nothing in the video's example code does that!

That's why the problem could be fixed by putting save/load on an interface outside the hierarchy.

If you squint right, the "inheritance" example code is actually a better example of composition than the "composition" example code!
So what's the real lesson of composition over inheritance?

It can't be about adding new functions, as that's just subtyping. If you implement that with composition vs. inheritance, the code winds up almost the same. Trivially interconvertible, no maintenance difference.
Instead it's about overriding existing implementations.

Overriding is scary. Every caller is suddenly doing something else.
For the counting hash table example, if you override put() to increment a counter, then it will also get incremented during a rehash. Or maybe not. That's an implementation detail. Can change on a whim

The composition version calls into the original code instead, and is robust
So that's what it means to favor composition over inheritance. Overriding existing implementations is dangerous
So when do you need to? When is true inheritance really required

That's a profound question which solves a major puzzle of software engineering.

It also has a short, simple answer
When there is bidirectional dependence between the base and child class.

That's it. That's what true inheritance is for. When composition fails.

But most uses of the "extends" keyword in mainstream languages are just subtyping and are a lot more like composition. So keep it up

• • •

Missing some Tweet in this thread? You can try to force a refresh
 

Keep Current with Jimmy Koppel

Jimmy Koppel Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

PDF

Twitter may remove this content at anytime! Save it as PDF for later use!

Try unrolling a thread yourself!

how to unroll video
  1. Follow @ThreadReaderApp to mention us!

  2. From a Twitter thread mention us with a keyword "unroll"
@threadreaderapp unroll

Practice here first or read more on our help page!

More from @jimmykoppel

Dec 7, 2022
1/

Had a blast Monday giving a code-review guest lecture for MIT's 6.1040 "Software Studio" class with Daniel Jackson. Now my head's full of examples of good and bad frontend code.

n^2 likes = n+1 examples of making cleaner and more robust frontend code

First one's free. Image
2/

First example:

What does this code do?

Say it in plain English.

It checks if something is going to happen less than three days from now.

But what does ity say?

It says: take the start time, subtract the present time, divide by some big number, and then compare to 3. Image
3/

Can we make the code say what it means more directly?

Let's look at the words above. "Days." "From now." Let's put those in the code

Like so

1st time I saw this snippet, I thought it was checking things in the past, not future. But one does not confuse "until" with "since" Image
Read 33 tweets

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just two indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3/month or $30/year) and get exclusive features!

Become Premium

Don't want to be a Premium member but still want to support us?

Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal

Or Donate anonymously using crypto!

Ethereum

0xfe58350B80634f60Fa6Dc149a72b4DFbc17D341E copy

Bitcoin

3ATGMxNzCUFzxpMCHL5sWSt4DVtS8UqXpi copy

Thank you for your support!

Follow Us!

:(