
Moving Beyond the OOP Obsession - vog
http://prog21.dadgum.com/218.html
======
sparkie
I don't disagree with the author's sentiment about inheritance (or OOP in
general), being used and taught wrongly, but I still think it's a necessary
tool to have available.

Without inheritance, as soon as you want to cast mixer to something else,
you're either relying on binary wizardry by the compiler (reinterpret_cast.
ie, undefined behaviour), or you need to break encapsulation to copy the
fields over from one object to another.

Of course we could use an opaque pointer to our objects instead, but if your
solution is to cast anything to (void*), where could that possibly go wrong?

OOP inheritance is pretty much doing that, but in a constrained, statically
enforced way, which prevents programmers from making elementary mistakes or
trying to make assumptions about the way hardware works.

Of course, the last example of the singleton works, but it also doesn't help
to explain why we might use singletons in OOP. If we assume we have both a
hardware mixer and a soft mixer which both have the set volume method, we
wan't polymorphism so we can treat them equally. In the author's solution, we
must treat each specially at the call site, which also violates our
open/closed principle - we want to add new mixers without hacking (and
breaking) the existing code.

Still, I pretty much agree that we should rethink the way these are taught.
Perhaps every student should write his own OOP language before being let loose
with it.

~~~
rlidwka
> Without inheritance, as soon as you want to cast mixer to something else,
> you're either relying on binary wizardry by the compiler

Why would you want to _cast_ mixer to something else? What real-life task does
it solve?

> If we assume we have both a hardware mixer and a soft mixer which both have
> the set volume method, we wan't polymorphism so we can treat them equally.

Polymorphism isn't OOP feature. You can have overloaded `mixer_set(struct,
int)` without any OOP wizardry involved.

~~~
scomment
> Why would you want to cast mixer to something else?

Did you ever heard about interfaces? You can have a IMixer interface, a Mixer
baseclass and some concrete mixer classes depending on your task. Like null-
mixer for mocking, software mixer for legacy computers, hardware mixer with
GPU support, etc. Use your imagination, Luke!

~~~
chipsy
Or you could just have data. The behavior of mixing is not going to change
because of those things.

------
stickfigure
We actually used to write "OO" C code like this - lots of it - back in the Xt
Toolkit Intrinsics days. It sucked. Writing GUI systems in C++ was a massive
improvement. Sometimes syntax matters.

------
golergka
I've encountered this code a lot in C, and every time I thought that this
style of

> stuff_do_something(stuff, some_parameter)

_is_ OOP and identical to

> stuff.do_something(some_parameter)

, although in language without support for OOP (of course, you can hack OOP on
top of C with preprocessors and stuff, but let's pretend we forgot about that
embarrassing abominations). And every time I saw that I wished that I could
type the second one instead, just because of how more natural it feels.

~~~
AndrewDucker
Exactly. OOP is: a) A code naming/organisational issue b) Some formalisation
of structure, so that developers can specify what is/isn't allowed in their
code.

Both of thise have advantages and disadvantages, and the structure can be
over-formalised and made too complex. But this doesn't make OOP bad. It makes
bad design bad.

~~~
jdminhbg
Well yes, when you redefine "OOP" to mean "well-organized code," then all
well-organized code is object-oriented. That's not what people mean when they
refer to OOP though -- they're talking about data+behavior encapsulation,
inheritance, message-passing, etc.

~~~
marcosdumay
OOP is not "well-organized code". It is a specific kind of code organization
that derives a good part of its value from being universal.

------
Nutmog
What baffles me about OOP is that massive aspects of how to use it have
changed, and that change happened _after_ it gained popularity as a good
technique. How could it have become popular when people were doing it wrong?
The article mentions inheritance, but there's also heavy vs light classes.
When I was taught OOP, an object knew how to do all the things to itself. It
could draw itself on the screen, modify itself, save itself to a file, etc.
Now that's turned on its head and is bad practice.

So if OOP was great with inheritance and heavy classes, how can it now be bad
with inheritance and heavy classes? Were the original OOP evangelists doing it
wrong and promoting something they hadn't actually tried enough to discover
its problems (ie hype)? Was it just misunderstood and inheritance has always
been known to be something to avoid and light (single public method) classes
always been a good idea but computer science professors didn't understand it?

~~~
al2o3cr
"Was it just misunderstood and inheritance has always been known to be
something to avoid and light (single public method) classes always been a good
idea but computer science professors didn't understand it?"

Could be. Or it could be that it's possible to write working programs with
many different methodologies and 90% of what developers argue about is fashion
not substance...

------
CyberDildonics
If you need an interface to your data, use structs/classes.

If you need genericness when the size of the data doesn't change, use
templates.

If you need genericness when the size of the data does change, use
inheritance.

If you need genericness with respect to part of an algorithm, use lambdas.

~~~
whatnotests
Thank you for succinctly putting this to words.

------
dboreham
The author seems to genuinely not know that this is the original motivation
for C++ -- to provide syntactic sugar and additional type safety to the very
techniques he describes, which were (and still are) widely used in C. It is as
if I am reading a "Software The Onion". Hmm...checks date...

------
exprx
>Now here's what this would look like in C++ without using objects:

    
    
        mixer_set_volume(m, 0.8);
    

What is m, if not an object?

~~~
hintingonwhoiam
The point is not a lack of objects but a lack of OOP. Yes, there are "objects"
but there is also a separation between objects and methods etc..

The issue with m->set_volume(.08) is it becomes difficult to tell what happens
inside set_volume() because in the method scope you have access to the
internals of the "m" object, not just the interface.

With mixer_set_volume(m, .08) you have ".08" and "m" but only the interface
"m" exposes anywhere else. Thus it becomes easier to reason about effects.

~~~
nlawalker
Can you expand on this? I'm not sure I follow, but maybe there's something
particular to C++ here that I don't get as I'm not well-versed in it.

>> The issue with m->set_volume(.08) is it becomes difficult to tell what
happens inside set_volume()

Isn't that the point? That you shouldn't have to care what happens inside
set_volume? If mixer was designed and implemented well, then set_volume (along
with the rest of its interface methods) should consistently and correctly
handle its internal state.

~~~
hintingonwhoiam
Whether you are dealing with OOP, functional, or some other pattern it is
always the point to create abstractions which you and others can forget about
how they work.

Thus m->set_volume(.08) and set_volume(m, .08) should not require you to
understand what happens internally as the user of either.

More generally in programming that is the point.

My only point is that of scope and essentially search space -- set_volume(m,
.08) can only access the public interface of "m". While, m->set_volume(.08)
could do almost anything to m. In a perfect world, with perfect programmers
thinking the same way about what "set_volume" means or should do the
separation of state and action would be less valuable.

This not to say OOP is > Functional or vice-versa. I think there is a place
for both but that is a MUCH larger and more nuanced conversation :)

------
vannevar
You could generalize the described approach even further and have a single
global function called 'message', so that your entire app consists entirely of
statements like:

    
    
        message(receiver, msg)
    

Sure, it's encapsulated, but it's hardly modular. The author knew not to do
this because he's undoubtedly already had a lot of experience with OOP. So
writing OOP-like functions comes easy to him. I'm not sure that would be the
case for a beginner, who could also go to the other extreme and have a
different function for everything, even if two methods differ only in their
arguments:

    
    
        add_one_to(number)
    
        add two_to(number)
    
        etc.
    

The point of OOP is that it provides some guidance in navigating between the
two extremes, and tools to manage modularity and redundancy (like inheritance
and composition). Encapsulation isn't the sole benefit.

------
whoisthemachine
I agree with this post, and especially the main focus of the post, which seems
to be: teach the basics before bogging students down in the crazy terminology-
heavy industry we live in.

~~~
Chirael
Yes absolutely. I learned OO with programming in the early 90s, around the
birth of the OO religion. So it's definitely in my mental toolbox if needed...
But in practice I'd say I rarely, if ever, need it. The only time it's come up
in the last 5 years was during a job interview, when I mentally did an eye
roll and thought "oh god OOP stuff again" Granted, I do more glue programming
and scripting, vs full-fledged app development. I'm sure if I was doing
Android apps I'd be using ActiveWindowAppAdapterFactoryConstructor (q.v.,
programming in the kingdom of nouns) but thankfully that's not something I
have to do (yet).

------
CuriouslyC
Personally, think object oriented programming gets a fair amount "right". That
isn't to say there aren't problems.

Specifically, classes as a mechanism of packaging data together with all the
functions that act on that data is a good idea. Additionally, I think classes
are more intuitive and generally tend to be syntactically clearer than their
functional equivalent, namespace factories (though less semantically
explicit). Fluent style chaining of method invokation is also a lot easier to
read than nested function calls in most languages.

The biggest issue I have with classes is the concept of constructors and
destructors. These are semantically unclear and basically break multiple
inheritance. Aside from that, in dynamic languages classes also encourage
people to write code that checks class type, which is both brittle and
potentially limiting, depending on the context.

------
DanielBMarkham
I've been saying this for years. Historically, yes, OOP has its own roots. But
for all effects and purposes, C++ with headers controlling visibility is the
grandfather of OOP. If you got that, then you've got OOP basics. (And, as the
author points out, 90% of what you'll ever need)

There's another way of "going beyond OOP" that bears some thought, and that's
growing a program by incrementally adding functions, then grouping the
functions into modules.

This is actually the same point as the author is making, but looking at it
from the other way. It occurs to me that if we started with writing code using
pure functions, over time those functions would naturally accumulate into
cohesive modules. A methodology that taught this could well end up being the
TDD of the next generation of coders.

~~~
woah
This is how Node js development tends to be done.

------
CyberDildonics
No one technique scales on its own. Assembly, macro assembly, expressions,
functions, classes, inheritance, templates, closures, data flow, and even
message passing if you want performance.

Everyone keeps looking for the silver bullet, but ends up with answers that
are simple, easy, and wrong.

If there is a bullet at all I think it is accepting that software architecture
is made up of all these things + tools that give lots of extra information
easily + interactivity and small iteration times.

I think when most people are being overwhelmed with complexity they want a
silver bullet so badly they will believe that there is one against all
evidence to the contrary.

------
scomment
Okaaaaaaay, so if we left _everything_ what OOP gived us (properties^1,
generics, lot of good patterns^2, lot of abstractions for generic things, like
interface^3, events, higher level datastructures, delegates, namespaces,
modules^4 etc.) then we get C? Omg, thank you Captian Obvious! Learn OOP
first.

What a bullshit article.

1) C++ for OO example? Seriously, why??? Grab a modern language who have
properties at least. Even Delphi had it!

2) IMHO without OO patterns OOP worth nothing

3) I know, you can do interfaces in C++ with pure virtual classes, but you
miss the abstraction behind that.

4) Java JAR, .NET assemblies, no matter what they called.

~~~
mishchea
Modules, namespaces, interfaces, many other things on your list, also have
nothing to do with OOP.

------
jakub_h
I could take that text more seriously if it at least discussed the limitations
of the most powerful embodiments of OOP that we have today and not the
accidental limitations of languages that for one reason or the other ended up
not as good as they could have and force you to jump through hoops, as
evidenced by the very mentions of classes, constructors, private methods etc.,
none of which are fundamental to OOP but all of which were made fundamental to
certain languages.

~~~
hcarvalhoalves
I agree, but OTH you can be a Platonist and refute every criticism with this
argument. In the end the OOP you have is the OOP that has been implemented, so
judging the implementations we have to work on is more down to earth.

~~~
jakub_h
True. But when it comes to learning the basics of programming, you can always
pick better languages. There doesn't appear to a shortage of pedagogically
useful ones.

------
aikah
Not sure I understand the point of this article, especially in the context of
C++ where encapsulation with classes helps avoiding things like memory leaks,
dangling pointers and co. If you feel you need to code C style, use C, with
all the problem it might incur.

------
bitcointicker
Another good article expressing a similar opinion which some might not have
seen [http://blog.codinghorror.com/your-code-oop-or-
poo/](http://blog.codinghorror.com/your-code-oop-or-poo/)

~~~
ufo
"Object Oriented Programming" in Portuguese is "Programação Orientada a
Objetos". So for me the two categories are one and the same :P

------
w8rbt
There's a lot of non-OOP C++ outside of the classroom ;)

Procedural C++ is big in systems (and that's not just plain C compiled with a
C++ compiler). Templates, strings, built-in containers and smart pointers are
very popular and useful.

------
sklogic
Classes are among the worst ways of implementing modularity. Compare them to,
say, SML modules.

------
sklogic
A value, with a type. Nothing else. Stop highjacking everything into your OO
religion. If you take everything of a value that originated elsewhere, there
will be nothing left in the OOD.

~~~
heartsucker
> Stop highjacking everything into your OO religion.

The parent to your post seemed to have a legitimate question, and you're being
snarky. You could have left out everything after the first sentence or even
explained what that means in practice.

~~~
sklogic
It was a bad argument disguised as a "question". I rarely tolerate this sort
of a discourse.

