
A Healthy Hatred of OOP, or the principles of my message-driven framework - rlt3
https://bythehilt.com/articles/dialogues-guiding-principles-or-a-healthy-hatred-of-oop
======
jasode
Your essay is arguing against a strawman of what "good" OOP is supposed to be.
Your examples...

 _> Objects just aren't supposed to be reaching into each other with 'getters'
and 'setters' and messing with information. _

The getX() and setX() is an _anti-pattern_ of good OOP.

 _> Instead of using objects for compartmentalizing functionality, they were
just used as a holding pen for loosely related functions. _

No, good OOP has class/object with _both_ private state and associated
functions combined to provide a _public interface_ for clients to use.

(Although Java & C# (unlike C++) may have muddled this aspect because their
language specification does not allow "free" functions to live in a plain
namespace. Therefore, programmers are forced to use the "class{}" keyword with
static functions as a workaround. Maybe that's where your "holding pen"
characterization came from?)

 _> A traditional OOP approach uses shadowy architecture to remove the
responsibility of an object,_

No, good OOP tries to _push responsibility_ into classes/objects so they can
act as independent agents with minimal coupling to the outer context they sit
in.

I'm guessing your comments are based on seeing a lot of poor practices
masquerading as OOP which affects what you think OOP actually is.
Unfortunately, it's like trying to argue against Javascript because of overuse
of "eval()" or arguing the flaws of Haskell because variable names are often 1
character long.

There are definitely problems with OOP but they are not the bullet points you
mentioned.

~~~
rlt3
>I'm guessing your comments are based on seeing a lot of poor practices
masquerading as OOP which affects what you think OOP actually is

I personally feel that the current OOP model eventually devolves into the
bullet points you listed given enough complexity.

One reason why I think this occurs is that there is no concept of a 'message'
in OOP, only methods or functions of a class. There's explicit coupling even
when calling a method with no arguments because you know the method is valid
for that object.

Contrast this with the example of the 'listener' in the room. A speaker
broadcasts his message but the independent agents ultimately decide what to do
with that message.

The OOP approach calls "object->listen" on each listener. My approach simply
broadcasts the message and lets the objects determine how to handle it
themselves.

~~~
jasode
_> One reason why I think this occurs is that there is no concept of a
'message' in OOP, only methods or functions of a class. _

If you mean there is no formal/explicit OOP syntax in C++/C#/Java etc for a
"message bus" or "queue" for a decoupled publish/subscribe type thing, you're
right. Yes, Golang/Erlang have that concept a little more "baked" into the
language.

But that's still orthogonal to the supposed OOP flaws you brought up.

The C++/C#/Java approach to the missing "message" functionality would be
either to create a class with a managed buffer to "hold messages" for other
classes to write or read from... or use a library that interfaces with an
external messaging bus.

~~~
rlt3
>The approach to the missing "message" functionality would be either to create
a class

Yeah, I explicitly covered this. I don't feel like piling some 'controller'
object on top of other objects necessarily accomplishes what I'm after.

But it does work and I've used the pattern plenty.

------
barrkel
The OOP referred to in this article is certainly a straw man, but the
alternative suggested has problems too.

Teams that work well act almost like they're mind-reading one another. High
quality orchestration of disparate parts is in tension with encapsulation.

Actor-based programming is highly concurrent but in my experience it's harder
to reason about as it scales up. Emergent behaviour of interactions between
hidden states is sometimes the goal, and sometimes an unwanted side-effect.
Network protocols are tricky to get right for a reason; splitting everything
out into a shared-nothing message-passing architecture isn't a panacea.

I lean more towards explicit but immutable data structures, and referentially
transparent functions over those data structures. In this world, parallelism
can increase performance without observable concurrency. Concurrency is the
root of non-determinism; non-determinism should be avoided unless it's
inherent to the problem at hand.

OOP is a middle ground in this world, but it's ill-defined. Depending on
style, it can be stateful and imperative, functional or message-oriented. OOP
is not an absolute bad; with effort, it can be massaged, or herded, into
working patterns. But it's certainly not a universal optimum.

------
carsongross
_A traditional OOP approach would have much of the functionality taken out of
the player objects, using them simply to hold state._

I don't agree with that characterization. The author certainly has a point
that, in some languages in particular, like java, there tend to be massive
over-decomposition of problems into reams of factories, controllers,
controller factories and controller factory manager factories, but that isn't
OOP, that's due to cultural and syntactic issues with those languages. (I
know, I know, No True Scotsman.)

In the Rails world, which is a non-trivial component of the broader OOP
software world, there is a saying: "Fat Model, Skinny Controller" which is
much more in the spirit of what the author is advocating, despite remaining
OOP.

Again, this isn't to deny the authors general point, but I don't believe it is
bound to OOP, so much as it is to a certain style of OOP coding that arose
from early (java in particular) over-engineering and excessive decomposition.

------
ninjakeyboard
I made up the term 'object-oriented', and I can tell you I didn't have C++ in
mind

\-- Alan Kay, OOPSLA '97

------
rdtsc
Joe Armstrong's thoughts on how Erlang is more OO than OO languages:

[http://erlang.org/pipermail/erlang-
questions/2009-November/0...](http://erlang.org/pipermail/erlang-
questions/2009-November/047748.html)

Joe likes to be funny, so don't get upset and confrontational about it.

The central idea is this I think:

\---

I now believe the following to be central to the notion of OO.

    
    
          - Isolated concurrent things
          - Communication through message passing
          - Polymorphism
    

All the other stuff (inheritance, private/public methods, ....) has nothing to
do with OO.

\---

~~~
incepted
FYI, Armstrong thinks that OO sucks [1] so it's weird to see him claim his
language is a better OOP language than others.

[1]
[http://harmful.cat-v.org/software/OO_programming/why_oo_suck...](http://harmful.cat-v.org/software/OO_programming/why_oo_sucks)

~~~
rdtsc
... "Joe likes to be funny" ...

Besides this idea of taking a label away from something you don't like is also
a good strategy in general. He obviously doesn't think Erlang should do
multiple inheritance. He just points out languages that have been calling
themselves OO these years have been impostors.

Also not sure if I mentioned, Joe like to make witty jokes. So don't take it
too seriously.

------
markbnj
>> When I started learning C++ I was shocked. Instead of using objects for
compartmentalizing functionality, they were just used as a holding pen for
loosely related functions. Instead of communicating between themselves,
objects were operated on by some bigger parent object. I found it absurd and
fought it for a long time.

This has nothing whatsoever to do with C++. It's like blaming a microwave oven
because your kid put a ball of tin foil in it.

C++ is a great language when you are developing big compiled programs and need
strong metaphors for decoupling and modularity. Most developers today work on
distributed systems where the individual cooperating pieces that they write
are much smaller. Your 1000 line HTTP handler in python won't benefit much
from strong static type checking, but the linux kernel does, and so do a lot
of the infrastructure components we all take for granted every day.

~~~
wtetzner
The Linux kernel is written in C, not C++. C has static typing, but it is
definitely not strong static typing.

~~~
markbnj
Yeah I did not mean to imply that the kernel was written in C++. As to whether
C is "strongly typed" or not that is a matter on which we can disagree, as
there is no agreed-upon definition of what that means. In my view it certainly
falls on the strongly-typed side of the line when compared to the languages
most developers use today. The point of my response is that OO methods as
embodied in C++ were a response to the growing complexity of compiled programs
back when it was developed, and those principles definitely helped developers,
including myself, get a handle on that complexity.

------
paulddraper
One of the more ironic titles I've seen.

Alan Kay (progenitor of Smalltalk and OOP) has said on various occasions that
it should have been called message-oriented programming, rather than object-
oriented.

"I'm sorry that I long ago coined the term 'objects' for this topic because it
gets many people to focus on the lesser idea. The big idea is 'messaging'"

[http://lists.squeakfoundation.org/pipermail/squeak-
dev/1998-...](http://lists.squeakfoundation.org/pipermail/squeak-
dev/1998-October/017019.html)

------
nbevans
The same thing happened with REST, TDD and Microservices, etc. The term gets
hijacked by people that are less than skilled at executing it. And
unfortunately there are more unskilled than skilled people in software; so
usually the hijacked term wins the contest. It then takes decades of the
"original guy" sending out a BBS message / IRC message / vBulletin post / Blog
post / Tweet / HN comment / etc to try to correct people's understanding by
saying "actually, that's not canon!".

------
copx
Comment on the code:

As a Lua aficionado I hate to see stuff like this:

    
    
      Ball = {}
      Ball.__index = Ball
    
      function Ball.new (x, y)
        local table = {}
        setmetatable(table, Ball)
        table.x = x
        table.y = y
        return table
      end
    

Explicit setmetatable() call and manual __index setting? You can automate this
and hide all the metatable magic = less code to write, less potential for
bugs.

E.g. in my own Lua object system the above would be:

    
    
      Ball = Class()
    
      function Ball:Properties(x, y)
        return { x = x, y = y }
      end

------
KirinDave
I think that we suffer from a paucity of precise language around OOP.
Everything is OOP, everything is what Kay created, etc.

But that's clearly not the case, and so people have these radically divergent
systems of programming within the framework of "object orientation".

My read of this article and it is very message-passing OO to me. Its broadcast
mechanism is interesting, for sure. But it reads a lot like Erlang's
supervision tree without all that troublesome thinking about a network.

But it's approach is still very "OO".

------
daxfohl
The downside of message passing is debugging. No call stack so you can't trace
things back to their source.

~~~
SlipperySlope
An agent framework I built for my AI research has exactly that.

I use an additional message parameter, automatically inserted and maintained
by the framework, which is a list of the messages (FIPA style operation +
parameters) from the originating agent forwards to the point of debugging.
This gets voluminous and is gated by debug levels.

~~~
Diederich
Same here. The framework I've been building over and over for various
companies for the past 20 years has extensive debugging capabilities. With the
right 'messages all the way down' mindset, it gets extremely powerful.

------
amelius
The only good thing that OOP brings to the table is, in my opinion, access
control.

~~~
kevinavery
Also referred to in this context as encapsulation. OOP provides a method of
information hiding that allows implementation details to be changed later
without changing the public API.

~~~
abiox
one downside being that you risk creating obscured islands of mutable state,
complecting engineering efforts.

~~~
kevinavery
I view that more as a risk of using mutable state, not OOP. Regardless, I'd
rather have the mutable state contained in as limited a scope as possible.

------
sbov
Isn't this basically event driven programming?

------
koder2016
_> Objects just aren't supposed to be reaching into each other with 'getters'
and 'setters' and messing with information._

In pure Actor Model adding two numbers would probably involve 2+ actors, yet
Erlang is not doing this for some reason... I guess on a lower level
hardcoding messages makes complete practical sense.

------
lucb1e
Some meta feedback on the article: this font is too big to comfortably read on
mobile, fitting about five to seven words on a line (the typically recommended
line length is about 14 words).

------
qaq
How does this make fp? If we fill fp with plugs for 1 man projects with 1
watcher we'd have 1000s of entries a day.

------
andrewmcwatters
The less actual code I see in articles like this, and the more abstraction I
read about, the less I take the concept seriously.

In fact, all of this seems like bullshit to me. The actual code inside of the
repo is, well, object-oriented. How I interpret this is that the author seems
to have no idea what they're even talking about, and that they write more
about code than they write code itself.

Show me what you mean, don't just talk about it.

~~~
rlt3
I should have a tutorial out very soon. The documentation is not yet complete
but does have a few examples.

Also, of course it's object-oriented. The article is titled a "healthy" hatred
for a reason.

~~~
orillian
I just have one smallish question. Is the need to bench then add an actor the
only way you "allow" transfer of children between parent actors?

In similar systems that I have constructed in the past, I have used a number
of methods for passing actors in different states.

Pass a fully instantiated actor via a transfer process. Nothing changes for
the actor, beyond reassigning parentage.

Pass a cleaned actor via a similar process to the bench and add process. This
was used to allow an actor to be reduced to a resting state as it were. In
most cases you could think of it as a resurrection method that allowed
discarded actors to be reinstated with only specified base properties in
place.

Anyway, I don't use Lua at all, but I like these type of actor messaging
models. I look forward to reading through the rest of your documentation once
it's done.

O.

~~~
rlt3
>Is the need to bench then add an actor the only way you "allow" transfer of
children between parent actors?

Currently, yes. Since this is sort of an entity component system and that
actors can always create more children anytime they want, I suppose I just
always assumed that actors could be "spun-up" with any sort of functionality
and then deleted when not used.

Benching/Joining an actor is more for handling errors at runtime or for
debugging ("If I temporarily remove this actor will it solve my issue?").

------
CyberDildonics
TLDR: Terrible programming practices end up putting blame on labels and
languages.

------
andrewvijay
The more I read about functional programming the more I question why are
things this hard in traditional oops. If so many people have been doing oops
for so many years then it must have something that is easy to pick up or
something that is easier to work with. But after doing some functional
programming the number of lines are painfully less and the code is easier to
understand. I was thinking may be I was giving too much credit to FP but I was
not it's simply just the way things are. But why has FN been used only as an
academic tool and not as a goto programming paradigm? Can someone shed some
light on this?

~~~
lostcolony
Broad generalizations here, but from my understanding -

Back in the dark ages, the performance difference between imperative code and
functional code was too large for FP to gain much traction outside of academic
circles.

By the time the hardware was anywhere near reasonable, OO had become a thing.
People missed some of the key points Alan Kay had, latching on to the one
thing that was immediately understandable: objects could model the nouns of
your problem domain. That popularity meant that the mainstream was focused on
OO, rather than FP.

I went through college in the late 2000s, at a well respected university, for
computer science. I had classes devoted to OO(A/D/P); I had none devoted to
FP. If you were exposed to it, it was via having to learn a Lisp in the AI
class, or similar.

~~~
andrewvijay
Okay. That's a great way to put it.

