
How Class-based Programming Sucks (2011) - vimes656
http://loup-vaillant.fr/articles/classes-suck
======
barrkel
Class-based programming works great for GUI toolkits. In most other contexts,
the suitability is variable. OO is a horrible match for compilers, for
example.

The article is chasing down the wrong tree when he tries to build an Option
type in C++, though. The normal OO way to handle the same class of
functionality as ADT sum types is to use separate subclasses. What he's not
acknowledging is that OO and functional+ADTs both only handle half the
expression problem[1], in different ways. There's no absolute superiority for
either model. It depends on the domain.

Less mutability is good almost everywhere though. The lack of persistent data
types is a blight on almost all non-functional container libraries.

[http://en.wikipedia.org/wiki/Expression_problem](http://en.wikipedia.org/wiki/Expression_problem)

~~~
seanmcdirmid
PL designer here with extensive experience writing compilers in C#, Java, and
Scala. Pattern matching is nice but OO will get you most of the way and
filling the matching gap is simple.

The expression problem is much safer solved using virtual classes (using
traits and type members) in scala than with case matching. There are so many
OO solutions to this problem it's not funny; I think I had a small argument
with Wadler over this back in 2001 or 2.

As for persistent collection types, observable collections with undoable
operations are just as good, if not better because they can still support
mutability while persistent collections cannot.

~~~
barrkel
I've written compilers in C, C++, C#, Delphi, Java, ML and Lisp; targeting
x86, x64, JVM and MSIL. I was maintainer of the Delphi front end at Borland /
Embarcadero. Pattern matching isn't just nice; you end up with substantially
better typechecking, and doesn't need ugly patterns like visitors with their
inverted callback control flow, if you want to decouple e.g. type checking or
code generation from your AST classes. Visitors are implicitly closed to
extension unless you create very abstract visitors (and I've gone down that
path, it's not pleasant) - you lose a big chunk of the extensibility objects
give you over ADTs. (I'd prefer to use multimethods, but they are rarely
available.)

I think persistent collections, along with nice syntax for updating immutable
objects (i.e. cloning with a subset of changed attributes) are more practical
than having undo available. Immutable data types remove the burden of worrying
about who's going to modify the data type from under you, so it lets you share
subgraphs more freely. You don't need to worry as much about coupling, because
the things you give your state to can't modify it. A possible alternative is
mutable collections with snapshots or freezing, but I think persistent
collections are a better approach.

~~~
xerophtye
Wow. Don't mind us mere mortals please continue your discussion, it seems
really fascinating even though i hardly understand a word of it.

~~~
Nekorosu
I consider myself a mere mortal too but I can understand most of the
discussion.

------
choult
The thing about "Class based Programming" \- or Object Orientated Programming
- is that it allows you to model a problem domain in real-world terms. No one
approach is ever going to be perfect; OO being mutable makes it perhaps less
founded (on the face of things) on formal principles, but for a lot of large
codebases it can have a great beneficial effect on readability and
maintainability - cognitive overhead is, perhaps, reduced when you can
"ground" your understanding in real-life terms.

At the end of the day, pick what language and coding paradigms best suit your
problem domain and you as a coder. Pick right, and there's no mistake there.

~~~
danenania
OOP actually doesn't model the real world well at all. It seems to on the
surface, but it completely ignores time.

In the real world, everything is a process. Nothing ever stays the same or
stands still. No object is the same object from one millisecond to the next.

Immutable state isn't just a formal exercise--it's a more authentic model of
the world.

~~~
theseoafs
I'm sorry, are you arguing that immutability models the world more well than
OO because _no object in the real world ever stays the same_?

~~~
tomp
Yes. Due to Special Relativity, different observers perceive events (changes
to object state) at different moments, the state of the whole universe is not
consistent. Therefore, we model the universe using a sequence of immutable
universe snapshots, with different computational agents independently moving
through the (branching) timeline of snapshots, so that each and every one of
them views the universe consistently.

~~~
pmahoney
Most events humans care about happen in plain old classical physics, and no
computer is moving at some large fraction of light-speed relative to any other
computer. If you maintain synchronized clocks, everyone can agree on the exact
same order of events (which would not be true in a relativistic situation).

Now it turns out to be difficult to maintain synchronized clocks, and Lamport
timestamps and vector clocks are alternatives. The end result looks similar to
a relativistic situation, but (and I'm not a physicist), it seems wrong to
claim this situation is because of Special Relativity.

Thoughts?

~~~
tomp
Yes. I was half joking, half explaining why immutability actually is better to
model the universe.

In practice, replace Special Relativity with Network Problems.

------
xcthulhu
Okay, for one:

1\. Dynamically Typed Languages (LISP, Erlang, Smalltalk, Python, Ruby, and
Javascript) are all easier than Haskell, JAVA, C++ or any other typed language
for working with ADTs. Whether the language is OO or not isn't really
relevant. On the other hand, you loose type-safety/efficient representations.
But life is filled with choices, different tools are good for different things
at different times.

2\. You can have closures in a class based language. Here's some rather exotic
Python code that uses both for measuring the performance of iterators:
[https://github.com/wearpants/measure_it/blob/master/measure_...](https://github.com/wearpants/measure_it/blob/master/measure_it/__init__.py)

Smalltalk and Scala also have closures. It's not an either/or for classes vs.
closures in programming language land.

3\. There's more to concurrency than shared memory, so immutability is again a
weapon that is good for some battles. If you have an app which you've factored
into workers, unless they are on the same machine they'll need to communicate.
Having your data be serializable is more important than having things be
immutable in this context. What a worker does with data while it is handling
it can involve lots of mutation.

So everyone should take a big breath, and remember that there's no one way to
think about software and there's no universal rules, other than probably P !=
NP and stuff like that.

~~~
platz
At this point, it's probably easier to name the languages that don't have
closures as opposed to those that do

------
rowanseymour
Best (and most humorous) argument against Java's object oriented obession that
I've ever read is: [http://steve-yegge.blogspot.com/2006/03/execution-in-
kingdom...](http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-
nouns.html)

~~~
pjmlp
The funny thing is that many like to bash Java's OO model, and in the process
forget that Smalltalk, Eiffel, C# and many others offer a similar model.

~~~
astrobe_
What's really funny is to claim that the Java/C++ model is similar to the
Smalltalk model.

~~~
pjmlp
Kind of, yes.

You can map instance methods to normal methods in Smalltalk. And static
methods to class methods in Smalltalk.

Of course, you don't have the dynamism of sending messages, instead of
invoking method calls.

However given that Smalltalk is the originator of OO and everything is an
object, OO critics would feel in prison most likely. :)

~~~
Alphasite_
I thought Simula was the originator of OO?

------
arithma
I find a mix between Object-Orientation to model the problem, and a lot of
functional thinking in the 'solving' department to be the most comfortable.
The modernisation (as in taking features from the old languages into the newer
ones) of C++, C#, Java, Obj-C etc. are all liberal with this direction.

~~~
arethuza
I agree - in my experience object-orientation is at it's best at structuring a
representation of the problem domain and functional thinking fits well with
solutions. I've written a lot of code over the last few years that models
large scale industrial systems and the general style is very much functional
processes over immutable objects and this has worked pretty well.

------
rayiner
This is a very good article. The point about mutable state is key. Class based
programming encourages you to treat objects as little bags of mutable state,
instead of as values, and everything goes downhill from there. Its one thing
to not go all the way to disallowing mutation. Its another to encourage it to
be used pervasively.

~~~
jimmaswell
Prorgramming without mutating state is honestly just bizarre to me. Mutating
state is all a program does, literally.

------
pbsd
> You may even have to inherit a base class or implement an interface. Subtype
> polymorphism is a very poor substitute for closures. This is why C++
> algorithm library is unusable.

Does anybody understand what the author means by this? STL's algorithm library
does not use class hierarchies for anything. And they often take functions (be
they free functions, lambdas, or functors) as arguments.

~~~
nly
The author probably had (this was written 3 years ago) a bitter and rather
narrow view of OOP capable languages.

In C++ a class is just a facility of the language with many different
features. If you want immutable, value-semantic objects, then _do it_. If you
want a closure... well objects can be closures too. C++ calls them functors,
they can be immutable. In fact, C++11 lambdas are immutable by default.

His criticism of the STL is probably that they expose their mutation, rather
than hiding it in the architecture like pure functional languages. In C++ you
just have to hide the infrastructure yourself.

~~~
humanrebar
The overhead that is assumed unimportant by most functional languages (copying
is cheap, GC is fine, etc.) is intolerable in key situations and problem
domains. In C++ _all_ overhead must be optional.

That being said, nearly all C++ applications can benefit from immutable
classes, algorithms that take closures, and so on. But C++, like C before it,
is really just an abstraction of the hardware and OS below it. That hardware
mutates. That pool of memory changes size and locality. The closer your
problem domain is to the metal (especially drivers and highly-optimized code),
the more you appreciate mutable state, at least given the current state of
computing.

~~~
pkolaczk
Dealing with complex immutable data structures without GC is either extremely
hard or inefficient (and usually both). C++ standard library does not offer
any helping hand here either. Additionally C++ logical memory model (flat,
uniform memory) does not describe the hardware memory model well - it is
already an abstraction. An memory access isn't uniform and mutations can cost
you really very much. In some cases immutable structures + little copying is
often the way to go, especially when we aim at parallelization.

------
auggierose
In case you don't know ML, you should. Also note that though OCaml is the most
popular ML dialect right now, Standard ML is where it all started (PolyML is a
good Standard ML implementation:
[http://www.polyml.org/](http://www.polyml.org/))

~~~
JackMorgan
Or even F#, which is basically OCaml on the CLR. Very fast, fully supported
IDE, great if you're stuck in SLAs for CLR code, complete interop with C# or
VB.NET, it's the current hidden treasure of the .NET world.

~~~
pjmlp
Pity that Microsoft pushes it more for library code and not so much for full
applications.

But if it gets more use in the mainstream that way, then so be it.

~~~
profquail
The only difference between a "library" and a "full application" is that the
"full application" has an entry point where execution begins, whereas a
"library" does not.

Many large applications are implemented as a thin user interface (GUI, web,
services/APIs) which glues together a bunch of libraries (which is where all
of the real functionality is implemented). This doesn't only apply to F#, but
C#, Java, Python, etc.

The reason F# gets used for implementing libraries is because that makes it
easier to introduce into organizations with existing code in C# or VB.NET; a
new component or plugin can be written in F# and easily utilized by the
existing code, so the other developers in the organization don't need to
anything differently than if they were consuming another C# or VB.NET
component.

~~~
pjmlp
I do understand the reasoning behind it, just as a ML fan would like to see
the possibility of proper support for GUI/Web for pure F# applications.

But I fully understand it, on my enterprise world JVM == Java and .NET == C#,
except when doing small prototypes. It is very hard to use alternative
languages, as managers always look for coding drones.

------
draegtun
Also see: _The problem with OOL is not the OO_ by Carl Sassenrath (from 2009)
-
[http://www.rebol.com/article/0425.html](http://www.rebol.com/article/0425.html)

PS. Just submitted to HN -
[https://news.ycombinator.com/item?id=6900426](https://news.ycombinator.com/item?id=6900426)

------
swah
Relevant recent tweet by the creator of the Io Language, Steve Dekorte:
[https://twitter.com/stevedekorte/status/411045428361056256](https://twitter.com/stevedekorte/status/411045428361056256)

I suppose most folks here disagree?

~~~
rurban
Of course I agree with Dekorte. Having written compilers written in perl, C
and LISP - the ones in perl in pure OO, and the ones in C and LISP without, I
conclude that I rather add classes and methods to my compilers than trying to
improve it without. In the one written in C, classes are supported by the
intermediate VM though (dynamically typed, very similar to Io), which is still
better than having to write it in horrible C++.

------
alkonaut
I agree, mostly, with the conclusions. "Classes" as a method of code re-use is
dead. However, his conclusion that ML would dominate C# and Java as a
language, I highly contest.

The most important thing in my opinion is tools and platform support. Show me
a fast, good looking IDE with good autocomplete/intellisense/integrated
debugger and UI tools for ML. See?

Is there an abundance of libraries and api wrappers available (that doesn't
require you to do straight C-interop)? See?

Also: the design of a language should be done with the tools in mind. While
there is not much difference between norm(vec) and vec.norm() the latter is
the form that supports autocomplete. So even for functional languages, being
able to use member properties and member functions is an absolute reqirement
to support the tooling that we expect.

You _could_ say that F# dominates C#. It has almost the same tool and library
support, while having the features you expect from an ML type language.

~~~
likeclockwork
I'm noticing that whenever there is talk about any language that isn't Java or
a CLR language several someones pop up to go on about the tooling "we" expect.

The difference between norm vec and vec.norm() is that the function can be
used in a higher order function while the method would require wrapping it in
a lambda to achieve the same thing and would probably still break your tool's
ability to autocomplete if you used it that way.

You're basically insisting that an FP language needs to include an embedded OO
language to be usable.

------
al2o3cr
"The obvious conclusion is that ML simply dominates Java (and C#) as a
language. Time to switch."

The obvious conclusion is that any statement that contains the phrase "the
obvious conclusion is" is 100% BS, including this one.

------
toolslive
mutable state is not a problem per se. _Shared_ mutable state however, is a
recipe for disaster.

There are other problems with Object-Orientation. For example, it tends to
scatter allocation which has performance impact. ( see this nice presentation:
[http://harmful.cat-v.org/software/OO_programming/_pdf/Pitfal...](http://harmful.cat-v.org/software/OO_programming/_pdf/Pitfalls_of_Object_Oriented_Programming_GCAP_09.pdf)
)

If performance is not an issue, I'd guess the price you pay for OO is that you
eschew parallelism and concurrency.

~~~
jeremyjh
Any code that operates upon your object with "private" state still has to
account for the fact that its methods are not referentially transparent. E.g.
I have to open a connection to the database before I can send commands through
it, and so now I have to check if its already open everywhere I use it. So
that is definitely shared state, but I guarantee you that a lot of people
think a private variable means it is not shared.

------
mtdewcmu
A language can't suck just because it isn't Haskell or ML.

~~~
matjazmuhic
It's funny how people blame the language when they are the ones who made a
mess. :)

On the other hand, there are languages that make it easier for you to screw it
up and the ones that try to prevent that.

But there's no bullet proof language.

~~~
mtdewcmu
A bug-proof language is like an uncrashable car.

