Languages on the rise like Rust and Go are being quite vocal against inheritance and many engineers seem to agree. Why? And is it the fall of inheritance?
These “OOP is bad, here’s why” type of articles often can be simplified to the pattern of “here’s a terrible example of OOP, and here’s a very good functional solution of the same problem”.
On small scale, OOP just makes things way more complicated than it should be. On larger scale however, it works quite well, especially if you know where to break the rules.
Something doesn’t need inheritance? Don’t use it! I even use structs in D, which often speed up things by a lot, especially since they’re not ref by default.
One big issue I’ve seen to come up again and again is the programmer not knowing how to handle functions, that need to be called many times. By conventional OOP wisdom it’s done something like this:
class Foo { void doTheThing(Param p) { //doing the thing } } [...] for (int i ; i < timesToDo ; i++) { foo.doTheThing(param); }
However, we can move the iteration into the function of the class, so we will still have the power of class interchangeability:
class Foo { void doTheThing(int timesToDo, Param p) { for (int i ; i < timesToDo ; i++) { //doing the thing } } } [...] foo.doTheThing(timesToDo, param);
Inheritance can replace complex condition statements. The class
Foo
in my example could be a basis for a thing, that has its own internal state, which is pretty common in game development. However most people are not being taught game development, but instead things that assumed to make money, which include the hottest new trend. When I was beginning to learn programing in college, I was told that we can say goodbye to .exe files, to say goodbye to installing programs to your PC, because everything is going to be web based, thanks to… Flash??? And Java applets??? Funny, it turned out to be JavaScript to be the winner, and now we have applications on our computers that are just glorified Chromium browsers running what are essentially interactive web pages, which got so widespread there are now coders not only afraid of all pointers, but also type declarations.In my honest opinion:
- OOP is okay. It’s not the catch-all solution as it was advertised back in the days, but neither if FP, aspect-oriented programming (was this even adapted?), etc. When structured programming came out and obliterated those awful
goto
statements, it was revolutionary. However, we might never replicate its impact yet again in our lifetime. Maybe it’ll never be replicated ever again. People are already failing to find the next iPhone, which are just nicer looking PDAs. - I’ve seen some some FP jank too. So far my favorite was a person, who managed to solve the use of atoms, by creating a struct they passed to each function, essentially creating a code that is as FP as it gets.
- A lot of attempt at avoiding OOP often end up with an attempt of reinventing it without using the class statement.
- Monoparadigmism, as I call it, is harmful. It makes its user to fall into the “when your only tool is a hammer” fallacy, and acting accordingly. It would be nice if we could have a single hammer that fixes everything, but that’s not the case. That’s why I love D’s multi-paradigm solution. You need classes? There’s a very friendly class system. You would like the same without being a reference value and the inheritance? You can just use structs. You need to ensure your data isn’t changing? Just add
const
everywhere. And so on, and so on, and so on.
Yeah. I read a lot less about large FP codebases than about large OOP codebases. Wonder why. /s
Some things just can’t be properly seen and evaluated in a tiny made-up example that fits in a blog post.
Plus, you have large teams with devs of different skills. Will they all be able to use the wonderful functional idioms that solve all problems and make everything great? Looks like more devs are able to use OOP, warts and all, to create some workable projects. Even if not supremely elegant.
- OOP is okay. It’s not the catch-all solution as it was advertised back in the days, but neither if FP, aspect-oriented programming (was this even adapted?), etc. When structured programming came out and obliterated those awful
I think inheritance served as a good stepping stone to features like traits in Rust. I spent most of my early career in C and C++, and given just those 2, I would pick C++ for classes alone, even though that’s nominally “picking inheritance.” Because with C++ classes you can define interfaces and compose those objects better than you can with just functions and structures in C (no callback functions and void pointers, thank you).
So it’s about the ergonomics of the language, and I think we as developers are collectively growing and exploring, figuring out what works and what doesn’t, and with Rust and Go we’re trying out those traits and interfaces we figured out in object oriented languages without dragging along classical inheritance. Given another 5, 10, 20 years, I’m sure we will have figured out what doesn’t work in Rust and Go and see new languages dropping those concepts in favor of newer, even more ergonomic ones.
I liked the idea of inheritance when you need to define a single thing and spawn it multiple times, but each class required exceptions, too many overrides to count, and usually I would spawn a thing either once or twice in my code, or 15000 times - neither scenario being optimal to having that many objects floating independently about. Sometimes an assoc. array is all you need.
We have been using OOP for a long time and have evolved our thinking through experience. We need to redefine a new paradigm that retains the good parts of OOP and removes the bad parts.
Considering most of the lines of code in the world are written in java, C#, C++ etc it’s pretty hilarious to claim that OOP and inheritance are dead.
As for go if you want to see what a large go codebase looks like go look at the kubernetes source code one day. Get back to me when you are done recovering from non stop puking.