
“A closure is a poor man’s object; an object is a poor man’s closure” (2003) - noblethrasher
http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html
======
derefr
My definition of an object is "an ADT that gets to 'decide', using private
runtime state, what to do in response to any/all attempts to interact with
it."

Which makes for a very simple test: if something is an object, you should be
able to send it a message that makes it change its mind about what messages it
accepts after that.

There's no obvious way to implement a behavior like this using the native
"objects" in nominally-object-oriented languages like C++ or Java. (But you
_can_ do so with the closure types from these languages. Or you can look
higher on the stack: threads with IPC queues, or POSIX _processes_ , are both
objects.)

But implementing this behavior is obvious in Ruby; this is how basic things
like Object#extend work.

And implementing this behavior is also obvious, oddly enough, in Erlang:
[http://joearms.github.io/2013/11/21/My-favorite-erlang-
progr...](http://joearms.github.io/2013/11/21/My-favorite-erlang-program.html)

In conclusion, Erlang is more object-oriented than Java. ;)

\---

And yeah, I know, this definition of OOP-ness sort of flies in the face of
decades of things people have said about OOP. Objects, under this definition
of OOP, don't obey any of the SOLID principles. They're slippery;
unpredictable; "alive."

But this was the original definition! It's the one Smalltalk fits; it's the
one LambdaMOO fits; it's what is meant by referring to Javascript as object-
oriented.

It's a shame we have this collision between meanings; having two separate
words for "OOP like Smalltalk" and "OOP like Java" would have saved language-
designers all a world of arguments from people who try to propose extensions
to a language in one category, assuming it's in the other.

~~~
noblethrasher
Your definition of an object is similar to one that I’ve used[1][2][3], which
is unsurprising since we got it from the same place.

But, now I define an object as any component with which you interact strictly
by way of negotiation (as opposed to command and control), and I finally think
I understand why Alan Kay says that the most important thing in OOP is the
message passing.

Thus, statically-typed languages like C#/Java/C++/etc. are also capable of
being object-oriented as long as you avoid setters and realize that some of
the negotiation happens at compile-time.

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

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

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

~~~
jakobegger
I'm not sure what's the problem with setters? In my eyes, they are just a
convenient shorthand for a common message. For example, Objective-C before
version 2.0 didn't have setters; so the libraries had lots of methods like
"setTitle:", "setDelegate:" etc. Setters are just a convenient shorthand. And
in ObjC and in Swift (I don't know Java/C#/C++ so well) you can override
setters to do whatever you like, so there really isn't much of a difference
between using a setter and sending a message -- it's just syntactic sugar that
makes code more readable.

~~~
noblethrasher
By “setter”, I mean a mechanism by which code that is external to an object
can gain _unmediated_ access to one or more of the object’s mutable instance
variables.

The big idea is that the sender should not be able to assume that the message,
`setFoo`, will have any particular effect with respect to the reciever’s
state.

~~~
DougBTX
At least in C# terminology, a "setter" for a public property is mediated
access, unmediated access would be a public field that can be set without
invoking a setter method.

Getters and setters in C# are method calls, like `setFoo` in Java, so can't be
assumed to be simple, they can do anything any other method can do.

~~~
noblethrasher
As it turns out, C# is a language that I know _extremely_ well; I'm aware that
setters can have arbitrary code. But, here's the problem: A programming a
language is medium for thought, which means that it promotes or prevents the
occurrence of certain ideas.

So, even though the compiler will accept any legal void-returning code within
the inner braces of

    
    
        public Foo Bar
        {
            set
            {
              //Do stuff
            }
        }
    

The fact that the client code is going to look like `Obj.Foo = whatever` will
practically foreclose on all but a small subset of possibilities.

------
jfoutz
I enjoyed building object systems in scheme. The closure way is kind of like
focusing on the code without worrying to much about the underlying data
structure. The object way is worrying about the data structure and the code is
secondary.

~~~
Tloewald
I think in effect you're saying that they're duals.

I think I would argue that objects bundle data and functions in a useful way
(when done right). Closures are more of an expressive convenience for
constructing functions on-the-fly. The overreach for objects is to consider
them as the only way to organize data and functions.

~~~
ionforce
What is a dual?

~~~
recursive
It's a table in all Oracle databases that has nothing in it. Also, it's this:
[https://en.wikipedia.org/wiki/Duality_(mathematics)](https://en.wikipedia.org/wiki/Duality_\(mathematics\))

------
hdon
I actually studied carefully the Koan from the Japanese Buddhist traditions a
few years ago. I can't tell you much about Japanese Buddhism, but I can tell
you a lot about the Koan.

Not all Koan share all the same themes with each other, but for my money, a
contemporary Koan really should try to embody all of a few important themes
that I find repeated throughout the Koan.

A lot of non-experts seem to want to emphasize how often someone is struck,
but for me I think this comes from a one of the most interesting themes in the
Koan: a sense of humor about failing to attain enlightenment.

When a person attains enlightenment in the Koan, it is often at the moment
when they are forced to acknowledge the duality of two opposing views, as if
in the fleeting moment between seeing Rubin's Vase or the faces in its
negative spaces.

In that sense, at least, it is a perfect Koan.

------
white-flame
Multiple closures can overlap in their referencing of some set of variables.
Objects can't really do this, so they're not _that_ similar.

Only the most simplistic application of closures (one unique set of
instantiated variable slots per closure) matches object encapsulation.

~~~
dllthomas
Objects containing references can share referents.

~~~
white-flame
That's a feature of the references, not of objects.

The sharing and overlapping of data slots is however an inherent feature of
closures.

~~~
dllthomas
> That's a feature of the references, not of objects.

That doesn't seem like an unreasonable way to draw the lines.

> The sharing and overlapping of data slots is however an inherent feature of
> closures.

Is it? When defining a lambda in C++ you can choose for things to be captured
by copy rather than reference. I _agree_ with saying that a function that
captures nothing is "not a closure", but I don't know that I'd say the same
about something that captures only by copy. Would you say that a language that
only supported capture-by-copy "lacks closures"?

~~~
white-flame
> That doesn't seem like an unreasonable way to draw the lines.

It's a turing tarpit otherwise, after all.

Regarding C++, I've not used the newer versions, but using that feature to
capture only copies would match what I said upstream, as a limited usage of
closures that would happen to match objects, while closures themselves can do
more. Capturing by copy also means that it's instantiating a new closure
variable slot specific to the copy, and is no longer closing over the original
variable, so it's an additional step on top of the fundamental closure
mechanism which would by nature be agnostic to private vs shared variable
slots.

------
lacampbell
While I've seen various methods in scheme to emulate objects with closures, I
haven't seen a good one from the statically typed FP camp (the ML family,
Haskell, etc). Meanwhile, objects are able to masquerade as closures very
nicely in statically typed OO object systems like Scala and C#.

So I lean more towards closure being a poor mans object than vice versa.

~~~
tel
OCaml, Objective Caml, has a built-in Object system. Objects are immutable
which prevents them from carrying identity (though mutation can be opted into
to recover this). They're also "just" row-typed records. Classes are a form of
constructor function which have inheritance for code sharing purposes. This
isn't emulating objects with lambdas, but it is a well-articulated idea of
what objects in a pure-ish FP setting might look like.

There have been many attempts to bring various forms of "object" into Haskell.
It tends to be either a very simple or a very messy affair. On the messy side,
strict purity blows up object identity again and there are only very messy
ways to recover it. This makes most OO such a pain that you're more likely to
factorize it into smaller pure components which appear more functional.

On the simple side, corecursive patterns are distinctly "object like" and are
used _all the time_. Laziness gives you infinite data structures which, in
effect, give you a limited form of mutability which can be _incredibly_
helpful while still be easy to reason about.

\---

Finally, I think that practically there is a strong case to be made for
introducing actor-like objects into Haskell. It has a great runtime and
exception system to support it, and it would allow a bit more structuring "at
the highest level" of application architecture. Today these are often managed
as imperative programs (built an IO chunk, execute it). This tends to work,
but Erlang did it better.

~~~
lacampbell
_OCaml, Objective Caml, has a built-in Object system. Objects are immutable
which prevents them from carrying identity (though mutation can be opted into
to recover this). They 're also "just" row-typed records. Classes are a form
of constructor function which have inheritance for code sharing purposes. This
isn't emulating objects with lambdas, but it is a well-articulated idea of
what objects in a pure-ish FP setting might look like._

Ocamls objects are great. I'm familiar with them and a big fan. I wish there
was a whole language based around them, ie everything is an ocaml style
object.

That having been said, they do feel odd and out of place in Ocaml, and people
don't seem to use them much.

------
SomeCallMeTim
Both are valuable under the right circumstances. A language that supports both
is stronger than a language that only supports one or the other.

In that respect, I think the koan is perfect. :)

~~~
runeks
What does "stronger" mean in this context?

According to this definition, assembly is stronger than Haskell, because it
contains stateful objects (registers), whereas a state-containing object
cannot be present in Haskell code, although one may appear when you run the
code in question.

~~~
SomeCallMeTim
Stronger means higher leverage for the typical programmer. Assembly language
isn't very high leverage (I say that having written several games
professionally in entirely assembly language).

Assembly language also doesn't natively support either closures or objects,
except in the sense that _of course_ you can build them from first principles,
Turing Completeness and all that.

Until someone proves to me that Haskell can be used in a reasonable way by a
"typical" programmer, I simply won't think about pure-functional when I make
general statements about languages.

I fully admit this may be a hole in my brain, but I don't understand how to
break down the problems I face on a daily basis into Haskell (or any pure-
functional language), so I just talk about the universe of languages that are
_not_ pure-functional.

I've looked at Haskell tutorials and gotten at least hip deep into the
language, by the way. I just usually end up dealing with problems that require
levels of complexity where FP tools fall down. Your mileage may vary.

------
cperciva
They're both wrong. Closures and Objects are both structures with function
pointers and delusions of grandeur.

~~~
taneq
Which is funny because I could never get anyone, when I first started
programming in C and everyone was raving about how great 'object oriented
programming' was, to tell me what 'an object' actually was. When I started
learning C++ I was somewhat disappointed to find out an object was just a
struct with some functions attached.

(It's kind of like when people told me about "user defined data types" and I
couldn't wrap my head around how you could create a new data type with all its
associated syntax. Then when I learned that they were just bundles of existing
data types, though 'oh is that all?')

~~~
lacampbell
I love OO - but C++s objects are so bad that most of the time I just end up
using functions-where-the-struct-is-the-first-argument, C style. If I'm
feeling particularly energetic I might use the PIMPL idiom. But naiive use of
C++ objects is absolutely painful for me.

All language constructs can be broken down into simpler ones, at the end of
the day. We might talk about how subroutines are just overrated assembler
macros. C++ isn't very clean so the fact that these fancy schmancy objects are
just structs + function pointers is very obvious. But when done cleanly, I'd
argue that an object is more powerful than the sum of its parts.

~~~
nkurz
_But when done cleanly, I 'd argue that an object is more powerful than the
sum of its parts._

I think I agree with your assessment of C++. What languages do you feel deal
cleanly with objects so they exceed the sum of the parts?

~~~
seanmcdirmid
I've seen objects recreated in Scheme and Clojure. They are really much more
common than most FP people appreciate, just look for noun-ish naming
conventions in your abstractions.

~~~
lacampbell
It's controversial for some people. OO is that horrible verbose enterprise
code with all the mutable state. And if you suggest that certain features or
patterns approximate OO they get very defensive.

There are certain famous FP language implementers that should probably read
what Guy Steele wrote in the topic, because listening to their talks I
strongly get the impression they haven't.

~~~
seanmcdirmid
One could also just use a synonym of object, like "entity." "Hey...we aren't
using objects here, we are using entities!" (Facepalm)

I saw Guy's growing a language talk before, but I don't think he's ever chimed
in on this debate before. Most people at his level simply except the world
without much bias, and are comfortable using object and functional styles when
necessary.

------
zumatic
'Qc Na responded by hitting Anton with his stick, saying "When will you learn?
Closures are a poor man's object." At that moment, Anton became enlightened.'

The cruel tutelage of Qc Na.

~~~
antonvs
The Zen Slap:

"If you read through enough Zen koans, you’re quickly struck, as it were, by
the number of those oblique lessons that end with a student getting slapped.
It may be delivered by hand, stick, sandal or goat bite, but the slap, painful
as it might be, is an act of compassion, a wordless reminder of the things we
know but can never seem to remember or practice for very long."

\-- [http://www.siliconbeat.com/2008/10/09/of-course-if-theres-
no...](http://www.siliconbeat.com/2008/10/09/of-course-if-theres-no-
enlightenment-a-zen-slap-just-hurts/)

~~~
dottrap
The TV show NCIS borrows from this philosophy. Gibbs always smacks the back of
his underling's heads when they do something stupid. But if he doesn't, they
worry he has given up on them. They also made it a point saying that smacking
the front of the head would be offensive.

------
jpfed
Really understanding this means knowing why a closure is a poor man's poor
man's closure.

~~~
white-flame
When you get to my depth, you'll understand that a closure is a poor man's
poor man's poor man's object. And it smells like a turtle, for some reason.

------
Animats
The main use of closures today is to create something you can pass to a
callback. In theory, you could pass an object, but the callback would have to
cooperate by accepting an object and an object method, or a reference to an
object method/object pair, in languages which support that. This requires more
standardization than one is likely to get.

~~~
saghm
I think of closures as a bit orthogonal to that; the definition of "closure"
that I'm used to is a function that "encloses" some data that is not an
argument (somewhat like a function with free variables in lambda calculus),
whereas a callback might only deal with its arguments. That being said,
sometimes I see the term "closure" being used in a way that I associate with
the word "lambda", which feels a bit off to me (I'm looking at you, Rust...)

~~~
Animats
A lambda is an anonymous function. A closure is a function which carries with
it some state. The two concepts are independent - you can have named functions
as closures, and lambdas that aren't closures. Rust does seem to tie the
concepts together syntactically.

Languages which support nested functions usually allow those inner functions
to be closures.

~~~
dllthomas
Yeah, any time you have a nested function you raise the question of "what can
this close over?" Sometimes the answer is "nothing", and that's not a
closure... but it's still an answer to the question so it makes some sense to
talk about it in the same breath.

~~~
Animats
Lambdas are just functions with different syntax. Closures imply keeping some
state around, and may require that some variables from outer scopes live
longer than they otherwise would. (That's what they're usually used for in
Javascript, where you want state kept around for a reply event.)

Closures are easy to implement in garbage-collected languages, but get
complicated in non-garbage collected languages. When an inner function
normally references variables in an outer scope, they're just references to
the stack. But if there's a closure that can outlive the outer scope, those
variables have to be saved somewhere.

With C++11 closures, you have to specify what you want to keep around and how
you want it kept.[1] Internally, C++11 creates an object to store the
variables you want to keep around. This can potentially create lifetime
problems, because you can save a reference to a variable, then keep the
closure object around longer than the variable being referenced. This creates
a dangling pointer. Rust has lifetime checking to catch such errors, but C++11
does not. See this Stack Overflow discussion of how not to shoot yourself in
the foot with C++11 closure lifetime undefined behavior.[2]

That's why it's useful to realize that closures and lambdas are not the same
thing. Lambdas are simple. Closures are complicated.

[1] [http://www.cprogramming.com/c++11/c++11-lambda-
closures.html](http://www.cprogramming.com/c++11/c++11-lambda-closures.html)
[2] [http://stackoverflow.com/questions/27775233/lambdas-and-
capt...](http://stackoverflow.com/questions/27775233/lambdas-and-capture-by-
reference-local-variables-accessing-after-the-scope)

~~~
dllthomas
I certainly don't mean that there aren't contexts where distinguishing the two
is vital to understanding. I just mean there are context where you'll need to
talk about both, and I think that's part of the reason they sometimes get
conflated.

------
ridiculous_fish
In Midori, objects are capabilities. This is possible because type safety is
enforced and an object's type cannot be forged.

It's easy to imagine a capabilities system built around closures. For example,
a capability to send on a socket could be an unforgeable closure that performs
that sending. Are there any systems that work this way?

~~~
chrisseaton
> objects are capabilities

What does 'a capability' mean? People seem to use the term to mean everything
from objects to threads.

~~~
the_why_of_y
In this context, it means the object capability model.

[https://en.wikipedia.org/wiki/Object-
capability](https://en.wikipedia.org/wiki/Object-capability)

Which can be used as the foundation of security.

[https://en.wikipedia.org/wiki/Capability-
based_security](https://en.wikipedia.org/wiki/Capability-based_security)

Relevant application in Midori:

[http://joeduffyblog.com/2015/11/10/objects-as-secure-
capabil...](http://joeduffyblog.com/2015/11/10/objects-as-secure-
capabilities/)

------
tempodox
Since objects are just specialized applications of closures, it's not too
surprising that you can reconstruct the basic idea (closure) from its
application (object).

------
amasad
I'm curious what's the history behind the use of Zen koans in computing? There
seems to be a lot of that.

Maybe because in programming there, often, isn't a clear right or wrong (like
in this case) so it pays to structure the problem/solution as a story to make
people "feel" rather than reason.

~~~
noiv
If I had to guess, I'd say it all started with GEB by Douglas Hofstadter. It
very well explains aspects of symbol manipulation using koans. However, there
might be another precursor.

~~~
dllthomas
ESR attributes the invention of the "AI koan" to Danny Hillis "while a student
at MIT". Hillis graduated in 1978. GEB was published in 1979.

[https://en.wikipedia.org/wiki/Hacker_koan](https://en.wikipedia.org/wiki/Hacker_koan)
[https://en.wikipedia.org/wiki/Danny_Hillis](https://en.wikipedia.org/wiki/Danny_Hillis)
[https://en.wikipedia.org/wiki/G%C3%B6del,_Escher,_Bach](https://en.wikipedia.org/wiki/G%C3%B6del,_Escher,_Bach)

------
ganfortran
Aren't they both just bundle of function objects + states?

------
lngnmn
Closure is more fundamental though. Add a structure (define an ADT) to a
closure and you will have an object.

The classic example is a closure with message-passing, which was the original
concept in Smalltalk.

~~~
lngnmn
Well, it seems that having a structure is the most fundamental principle.
While in reality structures formed and maintained according to the laws of
physics, in CS we have to explicitly define the rules, which is what Abstract
Data Types (which define Interfaces) are. Protocols and Interfaces are mere
generalizations of ADTs.

There are, however, at least some "laws of the universe" in CS. These are
Interrupts (the _only_ way to do I/O right), specialized Syscalls, etc. One
should respect them.

------
Ace17
One word: inversion of control.

------
sevensor
(2003) My favorite thing about this thread is that Guy Steele is involved, and
Guy Steele has a far better name than anybody else has ever had.

~~~
apathy
I did work with a guy named Max Kalashnikov at Google. That was a pretty "rad"
name, too.

~~~
sevensor
I've also known a "Ulises Cervantes" and an "Aristotle Socrates," since we're
trading awesome names :) Guy Steele is still my favorite, because I can just
picture a mustachioed villain shouting "curse you Guy Steele!"

~~~
apathy
The visual here is awesome. Although all good programmers are antiheroes in my
world, so I read that as a mustache twirling Guy Steele merrily evading the
bumbling cops. Practically the whole point of Real Programming is to evade the
limits of The Man. (Cf Mel: [http://www.catb.org/jargon/html/story-of-
mel.html](http://www.catb.org/jargon/html/story-of-mel.html) )

------
adamnemecek
Scala programmers are laughing from the side lines.

~~~
kbd
As Scala didn't yet exist when this message was written, its author was
missing the enlightenment Scala provides.

Would you please explain what about this amuses Scala programmers?

~~~
throwa38282
Scala is largely a set of iterative improvements with a syntax that's designed
to handle data workflows well. It's not a big deal, it's not that exciting, it
doesn't use all of the latest technologies, and that's why I think it has a
bright future.

~~~
kbd
This doesn't address closures vs objects at all.

