
FP vs. OO, from the trenches - llambda
http://blog.fogus.me/2013/07/22/fp-vs-oo-from-the-trenches/
======
jacquesm
For all those hating on this blog post: It's short, but it doesn't have to be
long to be useful, and apparently it is useful given a substantial chunk of
the comments here. If it wasn't news to you then ignore it, otherwise
appreciate that not everybody is quite as enlightened as you are.

HN has a tremendous reach these days, from pioneers in the field to total (and
often clueless) newbies. Fogus felt compelled to write down his thoughts,
someone else saw fit to post it and as of this moment 100+ people thought it
was useful enough to vote it up. If that's not validation enough for you then
remember that time when you spent half a day tracking down an endless loop and
you had to ask a more seasoned programmer to point it out to you.

Fogus is a respected member of the community because he tends to write down
what he thinks in a way that others _much_ further down on the totem pole can
grasp it too, his articles are not upvoted because he's 'well known' but
mostly because people find them useful.

If you feel like this article was 'devoid of content' or whatever slur you
feel like directing at it then please, write a better one.

~~~
semiprivate
That's not a real argument. You're essentially saying "respect because I said
so."

The irony is your argument is just as flimsy and opinionated as everyone
else's.

This article is devoid of content AND is written by a respected member of the
community but neither of those things make it worth reading.

The great moral of the story here is, if you let the internet bother you, the
internet will definitely bother you.

~~~
jacquesm
Content is not determined by the quantity of words on a page.

Some of the deeper links between linguistics and programming can be quite eye
opening and it does not require a large number of words to put those down. If
you find one of these, especially through your own work (as in 'from the
trenches') then that should carry some weight with you.

If you're doing this independently and re-discovering something that
apparently a lot of people such as you have already found out or learned about
elsewhere then indeed it is devoid of content. But I'll bet that it wasn't the
case for the majority of those that read it.

Lots of programming wisdom is so terse that we have acronyms for it (DRY for
instance), that does not mean there is no content there.

Anyway, enough said, I think it is worth reading, and worth 'grokking' for
want of a better word, in case you had not already discovered this. Naming
stuff is one of the harder things in programming, that different streams of
programming should lead to different groups of words being used to describe
the code should probably come as no surprise and yet I find myself amazed that
there are such deep connections.

~~~
olalonde
For me, the big confusion comes from the fact that if you simulate people, you
almost inevitably have to deal with data about people. How can those two be
mutually exclusive?

Without a clear definition or concrete examples of what the OP meant by
"simulate people" versus "data about people", the post is almost devoid of
information (to me; apparently, a lot of people understood what OP meant).

~~~
chongli
_For me, the big confusion comes from the fact that if you simulate people,
you almost inevitably have to deal with data about people. How can those two
be mutually exclusive?_

They're not mutually exclusive: the inverse is not necessarily true. This is
basically the entire point of the article. When you're just working with data,
don't use constructs which are meant for simulation. It's a subtle way of
saying "Don't model data about people (or any other piece of pure information)
with mutable objects; prefer values instead."

------
btilly
I have a version of this that I've used for years. _Objects make good nouns.
Closures make good verbs._

Software organized around nouns looks different than software organized around
verbs. Not better. Not worse. Different. Use what is appropriate.

~~~
dustingetz
_" Objects make good nouns"_

most 'objects' as they exist in today's OOP have methods, which makes them
both nouns and verbs. Idiomatic code in most of today's mainstream OO
languages doesn't make heavy use of closures, mostly only Javascript.

Anyway, the closures vs methods debate has been going on for decades is not a
closed topic[1], and the answer certainly depends on the language you're
using.

[1]
[http://www.c2.com/cgi/wiki?ClosuresAndObjectsAreEquivalent](http://www.c2.com/cgi/wiki?ClosuresAndObjectsAreEquivalent)

~~~
samatman
I don't believe this is a nitpick, but fully encapsulated OO provides only
nouns and verb _phrases_ that have a pre-specified noun. This is different
from data structures (nouns) with collections of functions (verbs) that can
act on many data structures in a consistent way.

------
bluehex
This post is nearly devoid of information. At least an example of what the
author means by modeling data about people v.s. stimulating people might have
helped. Most problems I encounter don't relate to people at all but maybe I'm
to just replace 'people' with 'things'?

~~~
city41
I'm puzzled why this is currently at the top of HN. I'm assuming the author
must be someone well known who I've missed out on, as that seems to be the
only way posts devoid of value push forward around here.

~~~
fogus
I posted it. Someone passed it to HN. People hit an arrow pointing upward.
That's how anything gets to the top of Hacker News.

~~~
city41
I'm not criticizing you at all. You're of course free to write whatever you
want. HN's tendency to upvote stuff from well known people just because they
are well known is a little annoyance I have with the site.

~~~
fogus
If that were the case for me then anything I would write would get upvoted in
bulk, but that's just not been the case. I wrote it because I thought it might
be useful to _some_ people and presumably it has been for those who've upvoted
it. On the other hand, those who have found it worthless have expressed so
very strongly in this comment thread. So it goes.

~~~
wicknicks
I do agree with bluehex: an example would definitely helped. It seems you have
a new perspective on the topic, which is great but the current version sounds
more mystic than informative. Here are one most confusing thought: Why are you
bringing in people into the equation? Are these end-users? Or programmers? If
they are end-users, why do they care what programming paradigm is used?

The idea about mixing OO and FP at different levels is a good one. Have had
similar experience.

~~~
fogus
I specifically tied simulation and people together to mean simulated-people. I
apologize that was not made clearer.

~~~
olalonde
I still don't understand. If you're writing SimCity ("simulated-people") you
should use OOP and if you're writing genealogy software ("data about people")
you should use functional programming!? I assume I misunderstood what you
meant because otherwise I have no idea how you arrived to that conclusion.

~~~
reeses
You're highlighting the immaturity of software construction.

Anecdote-Driven-Development will justify almost any approach, especially to
vague problems.

------
babarock
I'm a bit confused.

I always thought that FP and OO were orthogonal concepts and never considered
them mutually exclusive. To me, the antitheses of FP would be imperative
programming. Maybe I'm missing something?

CLOS, OCaml, Scala, I can think of many examples of languages that include
components of both FP and OO. Or maybe we're simply considering that OO means
this special paradigm used in C++/C#/Java (that really only claims to be the
true and only OOP by the commercial entities backing these languages)?

PS: I googled around a bit, this Clojure article [1] seems relevant.

[1]: [http://clojure.org/state](http://clojure.org/state)

~~~
cygx
Actually, FP and OO _are_ mutually exclusive to some degree:

OO comes from the imperative end of the spectrum (after all, objects are an
abstraction over mutable state), whereas FP comes from the declarative end (a
pure function is a relation between sets and mutability is a foreign concept).

However, most programming languages are impure and support both paradigms, so
you can get away with thinking about OO and FP as orthogonal ways to reason
about and structure your code; language syntax and semantics may of course
favour one concept over the other...

~~~
bad_user
OOP is not about hiding / dealing with mutable state, although it can be used
that way, but that's a perverted idea of what OOP is.

OOP is about subtype polymorphism [1] by means of runtime single-dispatch [2]
and modularity, as in abstract modules or components that help with
decoupling, a notion supported explicitly by SML, or exemplified beautifully
in the Cake-pattern used in Scala.

[1]
[https://en.wikipedia.org/wiki/Subtyping](https://en.wikipedia.org/wiki/Subtyping)

[2]
[https://en.wikipedia.org/wiki/Single_dispatch](https://en.wikipedia.org/wiki/Single_dispatch)

~~~
cygx
For me, OO means stateful objects communicating by message passing, and same
as asdasf, I consider it a way to structure imperative code. I don't consider
this a perversion - it goes back to Kay.

Your definition is of course an equally valid one that might be more
appropriate in certain contexts - it just doesn't fit my mental model of
computation equally well.

~~~
chipsy
I've developed the opinion, based in large oart on Kay's thinking, that the
biggest wins of OO are better represented as a form of protocol design. The
point of impedance comes in when you discover that not all protocols map
cleanly to OO systems - some are synchronous and others asynchronous, some
require more polymorphism than others, etc. Async message passing happens to
be one of the more flexible mechanisms for protocol design, but it's only been
relatively recently that industry languages have been considering it more
carefully, and then it's framed as "concurrency" and not a general
architectural consideration.

Likewise I see FP as a reactionary mechanism to write fewer and simpler
protocols, because when the data is immutable the problem can usually be
greatly simplified.

------
abecedarius
The lambda calculus was the first object-oriented language.
[http://www.cs.utexas.edu/~wcook/Drafts/2009/essay.pdf](http://www.cs.utexas.edu/~wcook/Drafts/2009/essay.pdf)
explains this and proposes a crisp distinction between OOP and abstract data
types.

~~~
davidcuddeback
I read that paper a couple years ago and it changed the way I see object-
oriented programming. All of a sudden, the dependency inversion principle just
clicked.

I hope I hit the upvote button instead of the downvote button. I'm typing this
on a shaky train and my browser will only zoom in so far.

------
williamcotton
If you have a simulation, where the outcome is not known and individual
Objects are keeping track of their own data and behavior...

VS.

...you already have data about a set of things and those things aren't going
to be changing their own data.

Think, Video Game VS. Data Visualization

~~~
williamcotton
If I have a run loop/game loop, I always use OOP.

I'm curious, has anyone ever implemented a run loop in a functional style? I
know there are recursive approaches to passing the time deltas and what not,
but it seems rather difficult to make video games with a purely functional
approach... Can anyone offer any insight?

~~~
klibertp
It is hard. At least that's what I read in:

[http://prog21.dadgum.com/23.html](http://prog21.dadgum.com/23.html)

EDIT: but not _that_ hard, according to
[http://prog21.dadgum.com/37.html](http://prog21.dadgum.com/37.html) ;)

~~~
williamcotton
Wow, thanks for that link!

The author's explanation was incredibly clear and I feel like I got a handle
on it!

Just 'lift' the relevant game state and pass mutatations along in a simular
way to how you might pass exceptions along with a promise based system... Then
it eventually feeds to a makeSounds() or an updateAnimations() or whatever!
That way the code can keep all related functionality in one place, instead of
spreading sound or animation related methods all over the code base
encapsulated in each object with its own logic! Brilliant!

~~~
williamcotton
And pass the previous frame state to the same functional pipeline,
recursively... Now I need to make an OOP vs FP game loop/physics engine in
javascript and compare and contrast the approaches! (Feel free to leave the
votes alone on this one, or down vote to oblivion, because I am just using HN
for note keeping so I leave the thought in context...)

------
gruseom
I find this post suggestive. The title—"from the trenches"—makes the important
point that this is a reflection _from experience_ on what seems to work best
where. That's more valuable and harder to come up with than it sounds, because
if you identify with a paradigm then you don't easily notice it getting in
your way.

I would like to hear a more detailed treatment of the distinction between
"dealing with data about people" and "simulating people". If these overlap
(and surely they do), then you get into a circularity where your favorite
paradigm leads you to see a problem its way, just as much or more than the
problem nudges you toward a paradigm for solving it.

On the other hand, my experience matches the OP's that OO's sweet spot is
close to its origins in simulation--where you have a working system that
exists outside your program, your job is to model it, and--critically--you can
answer questions about how it works empirically. When you aren't simulating
anything, OO is cumbersome because it requires you to name and reify concepts
that become "things" in your mind; these ersatz "things" continually draw
attention to themselves and get between you and the problem.

------
huherto
I don't think you have to choose one or the other. They are not mutually
exclusive. Furthermore, I still use Structured programming ideas along with
OOP and FP.

------
alipang
Kinda weak post, though what he said in point four vibes with me, where he
argues for using OO on the lower level with a functional API / abstraction.

This is a really underutilized design strategy. Much too often architecture is
discussed in OO vernacular, and as a result is made much too complicated. I
think we'll come to see OO as a low-level technique more and more.

~~~
ajanuary
Gary Bernhardt has a screencast [1] on DAS that proposes the opposite
architecture of functional core, imperative shell.

[1]
[https://www.destroyallsoftware.com/screencasts/catalog/funct...](https://www.destroyallsoftware.com/screencasts/catalog/functional-
core-imperative-shell)

------
mef
Anyone care to expand on the reasons for the guideline?

~~~
RogerL
Functional programming works great for processing data - you don't want to
change the data, and there isn't a lot of state. You largely write various
transforms and filters, which is right in FP's wheelhouse.

On the other hand, simulation is quite state-full, often has tons of little
details that you don't want to expose to the world (encapsulation), the thing
that you are simulating usually has a collection of varying behaviors that you
can represent via polymorphism or composition, they have attributes, and the
'engine' is often easier to write if you use dynamic(virtual
methods)/static(generics)/duck polymorphism to get your things to do their,
well, thing.

Which is not to say that either is undoable or really hard in the other
paradigm, but if I am simulating something I am often thinking of 'objects'
and doing things to them; the OO paradigm helps you program about that in a
very expressive way. Ditto for FP and functional programming - I'm thinking
about filtering and transforming data.

That is just my view of the author's article, with a caveat. I've seen
terrible, beastly simulations done in OO that basically thought that single
inheritance is how you spell OO. A single type hierarchy bites you so hard:
'Oh, I'm make everything a widget with draw/eat/process/whatever methods'.
Then requirements change, and widgets in this subtree need to do something you
thought only widget in that other subtree would do, next requirement has you
needing to reflect on who can do what, and so on. You end up with a huge Blob
object at the top of your hierarchy, or you endlessly end up with huge blocks
of RTTI/reflection to figure out what kind of thing you are dealing with, or
otherwise try to work around the problem that the world is not easily
decomposed into a single hierarchy.

In practice I find all of this terribly reductive. Need some small thing whose
behavior varies in well defined ways? Use polymorphism. Have a bunch of
stateful stuff that you need to keep track of? Encapsulation is nice. Want to
perform some operation on a large collection of data? Look to transform().
Need to make a lot of inferences and conclusions? Perhaps logic programming
will work there. Need to provide a framework where people can build larger
systems? Hopefully you are using component or services based ideas. And so on.
A programmer should have a bunch of tools handy, and use the best one for the
job. On the other hand, just about every person I interview opines that we
should inherit for re-use, and I silently despair.

~~~
chongli
_Have a bunch of stateful stuff that you need to keep track of? Encapsulation
is nice._

I think this one is open for debate. There are other models for managing state
which make things simpler to reason about than classical OO with
encapsulation. One such example is Clojure's epochal time model.

[http://www.infoq.com/presentations/Value-
Values](http://www.infoq.com/presentations/Value-Values)

~~~
RogerL
I think everything I wrote is a matter for debate. It's impossible to capture
all of software design in two paragraphs. Ten minutes ago I was writing some
code to display a baseball game - a quick Python hack, not a game or anything.
To me a class plus a bit of encapsulation for things like players, ball, the
field is 'just right' in a Goldilocks way. A bigger problem, a different
domain, and your link may make a lot more sense. My real point was that you
pick and choose based on your needs, not that some incredibly hastily written
list is immutable and not open to argument.

I would also suggest you (perhaps through equal haste in writing) made a
category error. Encapsulation != OO. For example, I can achieve encapsulation
in C just by putting variables in my .c file, and not distributing the .c, but
only the headers and a lib. I am not trying to nitpick, but wondering if
'classical OO' is part of your assumption.

In any case, I have never programmed in Clojure, and know nothing about
epochal time models. It looks interesting enough, but is it a tool I can
readily reach for if I am programming in C++, Python, or what have you? Will
others understand it? Googling provides only a dozen or so relevant links. I
think all in all I stand behind "Encapsulation is nice". It is nice, it is not
the only way or necessarily the best.

~~~
chongli
_I would also suggest you (perhaps through equal haste in writing) made a
category error._

Yes, indeed it was haste. Where I really want to draw a distinction is between
values and mutable objects (which may or may not use encapsulation).
Encapsulation is a leaky abstraction when applied to mutable objects because
the hidden state of some object may impact other parts of the system in
various ways. Values (and functions of values) are a much sounder abstraction
because they are referentially and literally transparent.

 _know nothing about epochal time models_

The epochal time model is a mechanism used to coordinate change in a language
which otherwise uses only immutable values (e.g. Clojure). It provides the
means to create a reference to a succession of values over time. This means
that any one particular list is immutable but the reference itself is mutated
to point to different lists over time. The advantage of this is that these
references can be shared -- without locks, copying or cloning -- because the
succession of values is coordinated atomically.

------
doorhammer
You know what has a lot less information than the blog entry? All the comments
about how little information it has.

Well... and this post, now.

I always come to the comments to throw a little balance or extrapolation into
my reading, and its disappointing to find people mostly just complaining.

Got a few interesting nuggets, though. So not all bad.

------
MatthewPhillips
Fogus makes the same point in Functional JavaScript (I highly recommend it).

------
reader5000
If you're doing something like agent based modeling, FP is great since you get
snapshots of your simulation "for free".

And whats the difference between e.g.

agents[0].location.x += 5;

versus

(update-in agents [0 location x] + 5)

------
Mordor
Long story short: the next big thing is a language which mixes both FP and OO.

~~~
platz
Then your next big thing is (especially) Scala

~~~
saosebastiao
Or Rust. Or D. Or Ruby. Or C#. Or Dylan. Or Lua. Or OCaml.

Lots of languages have concepts from multiple paradigms. What is the correct
mix of concepts is up for debate.

I honestly believe that Rust has the potential to become the perfect mix for
me, but OCaml and D are pretty good second places with the benefit of
exponentially greater stability/maturity.

~~~
platz
Sure, a lot of those languages (Ruby, C#, Lua) borrow some FP ideas, but I
think sprinkling in some FP ideas is different from F#, OCaml, and Scala where
FP seems to be more "font-and-center".

~~~
jes5199
My litmus test for whether a language really succesfully marries OO and FP is:
how well does a language blend pattern matching syntax and inheritance?

OCaml - basically only gives you pattern matching on primitive types. Object
types end up having dramatically different code style

Scala - any syntax that deals with types quickly becomes so complicated that
you can't explain it to non-experts

I don't know much about F#.

I've heard that Clojure's core.match grants pattern matching over abstract
interfaces in a nice style. It's not an official part of the language, yet,
though.

~~~
chris-martin
What is complex about Scala's pattern matching? x matches the value x, x:A
matches instances of A, A(x) matches if A.unapply(x) evaluates to a Some, and
_ matches anything. Erasure throws a wrench into it, but otherwise it's pretty
straightforward.

------
waxjar
Four footnotes on a two paragraph article?

Guidelines seem sensible though.

~~~
reeses
Think of it as four powerpoint slides with one "source" each.

------
jb55
I've always viewed OO as a nice optional UI for most programmers. Given an
object to mutate and call methods on seems to click for most people. I tend to
go for a more functional style internally for the composibility and
maintainability properties you gain.

------
pdog
For actor-based programming in Clojure (complete with real lightweight
processes, selective receive and an Erlang-like API), look no further than
Pulsar:

[http://puniverse.github.io/pulsar/](http://puniverse.github.io/pulsar/)

------
eternalban
FP makes an excellent backend -- architecturally speaking -- for OO-, REST-,
front-ends, and a most excellent front-end for Relational systems. (Haskell,
for example, would be a dream language for sprocs.)

------
lispm
I would propose the opposite.

------
the1
is facebook.com about people or simulating people?

------
michaelochurch
One thing that bugs me in the imperative vs. functional debate is that we
(functional programmers) often show people a side-by-side comparison with 20
lines of imperative code, 6 lines of functional code, and say, _see, the
functional code is so much better!_ Well, to us, it is. Filtered through our
biases, it's much more intuitive.

I think we're wrong on one thing. Personally, I think imperative code is more
intuitive. It matches how people think of operational behaviors.

For a 20-line program that will never grow, I'd rather see an imperative
straight-line solution. FP wins when things get a lot more complex: various
special cases and loops within loops. Stateful things compose poorly.
Debugging a 300-line inner for-loop is no fun. Functional programming, done
right, means people factor long before it gets to that point.

Factories and Visitors prove what hellishness comes into being when one _doesn
't_ have those functional primitives, but this does not make the superiority
of FP intuitive or obvious.

Now, OO is so variable in definition that it's very hard to know exactly what
people mean. There's the good OOP (Alan Kay's vision; encapsulate complexity)
and then there's bad OOP (overuse of inheritance, auto-generated classes,
Factories and Visitors).

One can conceive of core.async as an OOP win in Clojure; lots of complexity
(macroexpand a go block at some point) is being abstracted behind the simpler
interface of a channel.

~~~
chris-martin
> Personally, I think imperative code is more intuitive. It matches how people
> think of operational behaviors.

The masses agree with you, apparently. That's why they sit in their cubes all
day writing the same god damn re-implementation of map over and over again

    
    
        List<String> result = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            result.add(input.get(i).toString());
        }
    

instead of

    
    
        input.map(_.toString)
    

because functional programming is confusing.

~~~
pjmlp
Quite true.

I still don't understand why recursion is confusing to learn, as for me it was
obvious from day one. Then again I am good at maths.

Additionally, I had lots of fun doing Caml and Prolog when I was at the
university.

So even though I tend to do the typical boring enterprise JVM/.NET/C++ stuff,
I do welcome the FP contamination of those ecosystems. :)

However on my last project, I had to rewrite some LINQ stuff back to plain
imperative code, because few people on the team could manage it (LINQ). :(

~~~
chris-martin
I don't think recursion itself is difficult for most people to learn. The hard
part is translating recursive functions into procedures. The imperative coding
is what makes it confusing.

