
Goodbye, Object Oriented Programming (2016) - larryfreeman
https://medium.com/@cscalfani/goodbye-object-oriented-programming-a59cda4c0e53
======
thorell
I feel like the author doesn't understand the design part of OOD. Yes, you can
inherit yourself into rigidity. OOP doesn't prevent you from making design
choices that turn out to be bad, or are bad in the first place.

You can't reuse a class without reusing the whole world? That's the purpose of
dependency injection and depending on interfaces instead of implementation.
Decoupling.

Diamond problem? Okay, granted. But this still solvable in most languages with
interfaces.

I'm not really drinking the OO Kool-Aid here. I lean functional when I get the
chance, but this article reads like someone who's against rope because they
hanged themselves.

~~~
tabtab
If you have to tell too many people that they are "not doing it right", then
perhaps its too hard to do it right. If you build a paradigm that only Sheldon
Cooper can get right and complain when non-Sheldon's "can't use it right",
there is a bigger problem. It was supposed to make software design easier and
"more natural". If it takes lots of training to get right, that's not
"natural".

In general, I find OOP fairly well suited for building utilitarian API's, but
NOT for domain modelling. Domain modelling is where OOP failed bigly. When
UI/GUI's got more complex, they outgrew OOP's ability also and became a mess.
There seems to be a size/scope limit to OOP of subject matter.

------
jdonaldson
I doubt there's very few OOP hardliners on here, I'm certainly not. So, let me
play devil's advocate here a bit.

For the monkey-banana-jungle problem, it seems the developer started from a
monkey-banana type in a previous project, rather than just the monkey. It
seems in this case you would refactor the existing monkey-banana class, and
extract a plain "monkey" class that satisfies both projects.

I've done things like this in the past, and it's a headache, but it's less
painful than starting over from scratch. Most OOP languages will offer good
type checking for the refactoring process, and can easily catch any errors.
Also, dead code elimination can remove most of the unused methods and types
from a large codebase.

Diamond inheritance is a bigger problem. However the example they give is
terrible. Why wouldn't the powered device type be a common ancestor? One way
forward here is to use composition plus an interface to satisfy a new top
level type with shared functionality. It's ugly, but gives you some form of
consistency over types that need to be loosely coupled.

The fragile base class problem is equally stupid imho. Counting is managed in
two different ways from two different methods? Yikes! They also didn't think
to test this, and the change passed all of existing automated tests? Yikes!

You can shoot yourself in the foot with functional programming as well.
Anything that is shared can become fragile. Forming abstractions that cut
across multiple concerns is still problematic and error prone. It's common to
bring a jungle when you need a banana no matter what PL technique you use.

------
lkrubner
Also see Yegor Bugayenko's essay, "What's Wrong With Object-Oriented
Programming?"`

[http://www.yegor256.com/2016/08/15/what-is-wrong-object-
orie...](http://www.yegor256.com/2016/08/15/what-is-wrong-object-oriented-
programming.html)

and also the essay "Object Oriented Programming is an expensive disaster which
must end" had an interesting conversation here on Hacker News:

[https://news.ycombinator.com/item?id=8420060](https://news.ycombinator.com/item?id=8420060)

------
dvfjsdhgfv
I can't wait for his "Goodbye, Functional Programming" article.

------
_bxg1
This is overly simplistic and ranty. Sure, the OOP community got high on its
own supply for a decade or two and is now getting some well-deserved
criticism, but that doesn't make OOP the devil and it certainly doesn't make
all of its claimed virtues null and void (no pun intended).

The "Banana Monkey Jungle" problem applies to any paradigm that involves
defining things in terms of other things, including functions that call other
functions. You avoid it by writing code that's well-decoupled, no matter what
paradigm you're using.

The diamond problem is well-documented and has been solved or worked around by
numerous variations on inheritance (referring to methods by their class
explicitly, composition, etc.). It's a real problem with Java's "pure"
inheritance, but the author doesn't really add anything new to that
discussion.

The fragile base class problem is mostly a problem of poor interface
definition (read: documentation). Assumptions were made because there was
ambiguity, and then those assumptions went from true to not true.

"Object Oriented languages don’t make Contain and Delegate easy to do. They
were designed to make Inheritance easy." It's clear this author has spent most
of his time in Java. It's true that vanilla Java makes it difficult/annoying
to implement delegation, but C# can do it just fine, as can TypeScript and (I
believe) C++.

The Hierarchy Problem, once again, is solved by composition.

The author naively suggests that encapsulation is bad, but what he really
means is that hiding values behind their functions is bad (debatable, but not
crazy). Encapsulation is an essential building block of writing any nontrivial
amount of code. Functions themselves are encapsulation. Libraries are
encapsulation.

Finally, in the Polymorphism section, he actually bothers to distinguish the
principle from how it's been traditionally applied inside OOP, unlike
throughout the rest of the article.

OOP is flawed. OOP as passed down by the Java priests from On High circa 1995
was extremely flawed. But I'm weary of reading people's rants about it,
especially when they can't distinguish ideas like encapsulation and
polymorphism from OOP, and can't distinguish OOP from Java 1.0. Essays like
this throw the baby out with the bathwater. These days some of OOP's critics
are just as zealous as its proponents were in the 00s.

------
toomchsauce
Golang solves the problems talked about in this article. Except for
“encapsulation” which is really just... the author doesn’t like pointers which
is non specific to OOP.

Why is functional programming better? The author doesn’t really delve into
that

------
amarka
Goodbye Larry, see you in 5-10 years when OOP is back in style!

~~~
jstimpfle
Will it come back? Maybe it will be hot among the next generation of
programmers that failed to learn from the past. Just like the mistake that is
explicit asynchronous programming (e.g. callback hell in node.js) when
(cooperative) multitasking has existed for 50 years!

------
stagger87
I feel that whenever someone complains about OO, it almost always starts with
"I tried mapping everything to a class" and I always want to ask "Why?".

~~~
bb88
In Java everything has to be a class.

I prefer C++/Python style where things don't have to be classes. They can just
be independent functions.

------
pbiggar
Yes! This is basically why my new language is functional, and not OO. I bought
in the OO dogma in college, but programming in functional languages is just so
much easier.

~~~
whitepoplar
Any chance you can talk more in depth about this? I'm really curious! FP seems
wonderful, but there are few side-by-side code examples out there.

~~~
pbiggar
Sure. I presume you're asking about why FP is easier, though if you're
wondering about my language there's more info at https::/darklang.com.

I think the quote about the gorilla and the banana and the jungle is a really
important piece. It's just hard to compose things in OO languages unless
they're designed to be used together. Whereas in an FP language, you focus on
simpler primitives (arrays, hashtables, nullable types, and errors values
typically, depending on the language), and you have a ton of functions that
know how to work with those, so you kinda use them for everything.

A second reason is static typing (doesn't apply to the lisp family of FP).
Good static typing makes it very easy to understand what's happening, and
makes it hard(er) to make errors. For example, in OCaml, Elm and Haskell, it's
impossible to have a NullPointerException, which is the biggest bug class in
Java. Similarly, the biggest problem in a python/ruby codebase is "what
exactly is this thing I have", a problem eliminated by the type system as
well.

Of course, these features have a cost. It can sometimes be trickier to do
things that are easy in dynamic OO languages like Python (and of course
Haskell has layers of complexity so I don't recommend going near it), esp the
learning curve if you're not familiar with FP. But being in deep in a
functional codebase is much much easier than being in a deep in a java, ruby,
python, js, etc, codebase.

If you're looking to check FP out, I recommend Elm, ReasonML, or Clojure.

~~~
purvis
> about my language there's more info at https::/darklang.com.

I find it slightly reassuring that someone is actually working on a
language/compiler with PaaS features built in. I'd thought of doing that and
jotted it down in my notebook.. assuming it was just a crazy idea.

When do you plan to release an alpha version? I'd be interested in seeing it!

~~~
pbiggar
Alpha is probably out this year. We send periodic announcements to our mailing
list, there's a link at the bottom of Darklang.com. Also, we're hiring:
[http://darklang.com/careers](http://darklang.com/careers)

------
youdontknowtho
These posts are tedious, like a stereotypical newly converted non-smoker or
vegetarian cornering you at a party.

The same arguments about the diamond inheritance problem, and blah blah blah.
Funny gun-foot meme...check.

I'm not even saying it isn't true. I'm saying that it's boring. Functional
programming has it's own set of stupidity and anti patterns. If your favorite
language doesn't have any that spring to mind...give it time.

Queue the people saying OO is really message passing.

Then the Rust people. I guess the world has always been this way, but it makes
me think we are screwed as a species.

~~~
jstimpfle
People need to put it their way to learn. And to some readers these thoughts
will be actually new. That's how opinion/experience/knowledge spreads.

------
kazinator
Hello, OOP (2018)

I just recently wrote a Lisp compiler and assembler (for VM) using OOP.

[http://www.kylheku.com/cgit/txr/tree/share/txr/stdlib/compil...](http://www.kylheku.com/cgit/txr/tree/share/txr/stdlib/compiler.tl)

[http://www.kylheku.com/cgit/txr/tree/share/txr/stdlib/asm.tl](http://www.kylheku.com/cgit/txr/tree/share/txr/stdlib/asm.tl)

Even abused inheritance for logic re-use: see _defopcode-derived_ macro in the
assembler.

The OOP system is my own---now compiled. :)

It's a pleasure to use and makes the code look good. No bo

------
romanovcode
It is always seems kind of cute when someone discovers something new and
thinks it's a silver bullet.

On a side note, .NET is not a language, it's a framework, like JVM. In fact F#
runs on .NET and it is purely functional.

~~~
nathanaldensr
I'm shocked that in the 17+ years .NET's been around, we _still_ hear people
say that .NET is a language.

~~~
tabtab
They often really mean "common Microsoft languages such as C# and VB.net used
with Visual Studio". There's no common short way to say that (yet). "Microsoft
stack" is about as close as I can come.

------
salex89
I get what he is talking about, but to be honest alI never encountered a
situation where I intentionally or unintentionally got to diamond inheritance.
I just didn't... As for the add/addAll example, the smart thing to do is just
not put too much in the public method or just declare it final...

------
RealNeatoDude
This article is about OO+[bad language design/patterns].

You can do OO without sharing state with your parent(s).

------
awinter-py
not sure FP handles fuzzy categories better than OOP

isn't fuzziness why we have topic models and, more generally, ML?

------
tomphoolery
the year annotation on this article got me :)

------
kazinator
> _For efficiency sake, Objects are passed to functions NOT by their value but
> by reference.

What that means is that functions will not pass the Object, but instead pass a
reference or pointer to the Object._

This is confused garbage, and goes rapidly down hill from there.

Reference semantics is required for OOP. The reference is necessary because
that _is_ the object. The object's "value" is a concept from the record or
structure types of non-OOP languages like C and Pascal. If we pass the value,
we are not passing the object, but a copy.

In high level languages, we don't even see the reference as a separately
declared reference type; that is a low-level concept from "Blub OOP".

I'm surprised this blogger's Smalltalk experience didn't set him straight.

> _If an Object is passed by reference to an Object Constructor, the
> constructor can put that Object reference in a private variable which is
> protected by Encapsulation. But the passed Object is NOT safe! Why not?
> Because some other piece of code has a pointer to the Object, viz. the code
> that called the Constructor._

The charitable way to understand this bizarre nonsense is that because the
caller of the constructor has a reference to the object, it has access through
the reference to the object's "value", and by going through that reference, it
should be understood as bypassing the encapsulation of the container which
also holds that reference as a private variable.

This is laughably confused. Encapsulation means just that the binding is
private: the newly constructed object holds that existing object in a private
slot. Encapsulation doesn't mean that the embedded/aggregated object's
contents are also private to the aggregator. Those are protected by that other
object's class!

> _The Constructor will have to Clone the passed in Object._

Only in some very specific circumstances when it is necessary for this parent
object to have its own instance of an object similar to the one which is
passed in: either so that it can mutate this instance without having an effect
elsewhere, or else so that it has a snapshot facsimile of the passed object
which is immune from changes elsewhere.

Such a requirement doesn't always apply.

> _So much for efficiency._

When such a requirement doesn't apply, the construction of the similar object
or 'deep cloning' will not just be inefficient, but _wrong_. For instance
container object will expect the contained object to react response to events,
but instead it actually has a dead copy which isn't receiving calls from
anywhere.

It's clear from the semantics whether "we want to be composed of that actual
object" or "we want to be composed of a similar one, in a similar state to
that one's current state".

The second situation may require planning and design work. Indeed, not objects
can be easily copied.

Some other solution may be required, like splitting that object into some
state that is easily copied and some part that remains shared. This need not
even require a split, just a suitable copy operation.

Linux has clone() system call for processes with a bazillion flags to copy
this and not copy that; kind of the same thing. Sometimes we share the address
space and file descriptors and signal handlers, sometimes we don't.

------
praneshp
[2016]

(not that it adds any credibility ....)

~~~
sctb
Updated. Thanks!

------
_zachs
For anyone not wanting to read the opinion behind the click-bait-titled
article, here's the TLDR: the author never learned how to write OO code and is
now declaring it dead.

Every problem he brought up is easily solvable by writing good code. FYI, I'm
a big proponent of FP, but I'm not a proponent of disparaging things I don't
fully understand.

~~~
amag
> Every problem he brought up is easily solvable by writing good code.

I'm curious, how? Would you mind use one of his examples along with some good
code?

