Just reading the submission title instantly reminded me of "Anton van Straaten's Koan", and for good reason -- it's quoted in the submitted page, and indeed makes up the first 3 paragraphs.
Here it is:
The venerable master Qc Na was walking with his student, Anton. Hoping
to prompt the master into a discussion, Anton said "Master, I have
heard that objects are a very good thing - is this true?" Qc Na looked
pityingly at his student and replied, "Foolish pupil - objects are
merely a poor man's closures."
Chastised, Anton took his leave from his master and returned to his
cell, intent on studying closures. He carefully read the entire
"Lambda: The Ultimate..." series of papers and its cousins, and
implemented a small Scheme interpreter with a closure-based object
system. He learned much, and looked forward to informing his master of
his progress.
On his next walk with Qc Na, Anton attempted to impress his master by
saying "Master, I have diligently studied the matter, and now
understand that objects are truly a poor man's closures." 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.
Now I will be the first to admit that I usually just don't get koans. But I think I get this one. Objects and closures are equivalent in the sense that what you can do with one you can do with the other. However, for each particular case one may be better (easier to use, more natural, whatever) than the other. You should use which ever one is the best for each particular problem.
This is of course easier if you are using a programming language that natively supports both closures and objects...
The way I like to put it is that instances and closures are duals: a closure can do exactly one thing, while an instance can, in general, do several things. That's why, when invoking an instance, you have to supply a method name that says which of the several things you want it to do, while when invoking a closure no method name is necessary.
Of course it's not a hard-and-fast distinction: you can have a closure that dispatches on one of its parameters to do one of several different things, and you can have an instance with only one method. But it's usually valid.
If you think of a closure as only returning a reference to a function, but a closure can return anything. What if my closure returns an ssh connection to a new machine? A database? A program that generates programs? A hash of functions specialized to my calling arguments? How is a the function that returns a closure different from a constructor?
I think it depends a lot on the language's syntax and what sugar it offers. I believe there are choices you can make that make closures superior to objects in every possible way.
Consider this simple syntactic rule: `obj.x` <=> `obj("x")`. With this rule, the usual syntax for a method call, `obj.method(x)`, literally becomes the curried application of a closure, `obj("method")(x)`. You could also add a rule like `obj(x) = y` <=> `obj(set(x, y))`. Then you could define objects a bit like this:
point = (x, y) -> method ->
match method:
"x" -> x
"y" -> y
set("x", newx) -> x = newx
set("y", newy) -> y = newy
"add" -> (pt) -> point(x + pt.x, y + pt.y)
p = point(1, 2)
p.x = 5
print p.add(point(3, 4))
All closures. And the nice thing with that scheme is that meta-programming and reflection become completely trivial. Control over the interface is total. What use is there for "real" objects in this situation?
They are not exactly equivalent though. It is not possible to completely abstract away state changes with objects. You always end up with at least two calls that you have to keep track of.
A closure is a data structure commonly used to represent a first-class function (containing a function pointer for the code and some sort of structure mapping the environment's bound variables to their values). Implementing a language with first-class functions does not require using closures. You could have an interpreter that performs beta reduction on the syntax tree, and first-class functions would still behave the same way. So closures are an implementation detail.
In OOP, there are pieces of data that have operations associated with them. Two objects are free to have their own "version" of the same operation (same-named), and when you invoke it on an object, you get that object's version. In writing one of those operations, you have a handle on the thing you're operating on without having to take it as an argument. This specifies what result you'll compute and what side effects you'll cause by invoking an operation (i.e., the semantics). It does not specify things like where in program memory the code for that operation will live or how invoking it will work (implementation).
I like to see this as a sort of duality: closures are objects that have a single method (call) and objects are made of functions that can only capture one variable (this).
That's not a closure. That's returning a struct. That struct is an object that has several instance members that are functions, which you've created as closures, but note you're still returning a struct. To return a closure, you need to return a function type, which then has exactly one way to call it, which is the claim here about functions.
Of course you can dispatch anything you like within that call, turning a closure back into "methods", although in most languages that's a fairly painful way to operate even though if it is possible. Personally over the years I've come more around to tel's point of view, which is that as related as objects and closures may be, they aren't quite just two sides of the same coin, as further evidenced by the fact that pretty much all modern OO languages also include closures. If they really were the same thing in two guises somebody would probably have fully unified them by now, but they aren't the same thing. As much fun as the koan is, I think it's false wisdom.
You have to specify the language; there's no (useful) definition of type classes and interfaces outside of the context of a specific language that is specific enough to make reliable comparisons.
If you mean "Are Haskell type classes equivalent to Go interfaces?", the answer is no, Haskell type classes are substantially more powerful, even before you start turning on extensions. For instance, "Go" can not express the Monad typeclass at all.
As others have exemplified: it gets really hard to talk about this stuff outside of formal models. Especially if your goal is to talk about equivalency.
At this point I start trying to turn toward System F, but that's my hammer for this particular nail and I don't know an equivalent one in the object side of things. I'm certain you can express higher-level things in System F which are equivalent to interfaces. I know there's a translation of typeclasses to System F—it's called Haskell, har har—although you have to recognize that the "search" component of typeclasses will be lost.
Interfaces—at least in C#/Java—are equivalent to product types; they let you express the notion of conjunction within the type system.
Similarly, “implementation inheritance” (where every class is either sealed/final or abstract) is how we express sum types.
We can simulate type classes in C# by using implicit casts to abstract classes (interestingly, it’s not so straightforward to simulate the awesomeness of type classes in F#).
The key to all of this is to realize that “types” and “classes” are not equivalent, even though C# and Java conflate them.
Yes, it's not very formal and as others said it would need some definitions to make a useful result.
But actually I don't think that this duality is related to types: in a static language, the types of captured variables does not appear in a value's type. And for the object side, the type of instance variables is hidden behind the public interface too.
So it's really more about techniques for creating abstractions than how the values are composed together.
Conceptually they're both just a combination of some data and code that (usually) makes use of that data. I think a great example of this is function objects in C++.
Closures are used as objects quite a lot in R, as the standard structures are all actually immutable (to first order the only common user facing mutable things in R are variable bindings / environments, there are reference classes like RC and R6 but they are not considered core language). A lot of R users may not know this as value mutability is simulated through aggressive variable re-binding.
Wouldn't closure be more like a single-method-objectin a class that has no class methods?
A clojure carries its own states (variables) that it, only, can modify. While the states (variables) of an object can be changed by another method for the same object, or by a class method, or even methods from another object if it uses method variables.
Just reading the submission title instantly reminded me of "Anton van Straaten's Koan", and for good reason -- it's quoted in the submitted page, and indeed makes up the first 3 paragraphs.
Here it is:
Now I will be the first to admit that I usually just don't get koans. But I think I get this one. Objects and closures are equivalent in the sense that what you can do with one you can do with the other. However, for each particular case one may be better (easier to use, more natural, whatever) than the other. You should use which ever one is the best for each particular problem.
This is of course easier if you are using a programming language that natively supports both closures and objects...
The way I like to put it is that instances and closures are duals: a closure can do exactly one thing, while an instance can, in general, do several things. That's why, when invoking an instance, you have to supply a method name that says which of the several things you want it to do, while when invoking a closure no method name is necessary.
Of course it's not a hard-and-fast distinction: you can have a closure that dispatches on one of its parameters to do one of several different things, and you can have an instance with only one method. But it's usually valid.
If you think of a closure as only returning a reference to a function, but a closure can return anything. What if my closure returns an ssh connection to a new machine? A database? A program that generates programs? A hash of functions specialized to my calling arguments? How is a the function that returns a closure different from a constructor?
You can have several different functions that all close over the same state. This situation is analogous to an object with several different methods.
2 replies →
I think it depends a lot on the language's syntax and what sugar it offers. I believe there are choices you can make that make closures superior to objects in every possible way.
Consider this simple syntactic rule: `obj.x` <=> `obj("x")`. With this rule, the usual syntax for a method call, `obj.method(x)`, literally becomes the curried application of a closure, `obj("method")(x)`. You could also add a rule like `obj(x) = y` <=> `obj(set(x, y))`. Then you could define objects a bit like this:
All closures. And the nice thing with that scheme is that meta-programming and reflection become completely trivial. Control over the interface is total. What use is there for "real" objects in this situation?
Your approach does not support polymorphism.
2 replies →
They are not exactly equivalent though. It is not possible to completely abstract away state changes with objects. You always end up with at least two calls that you have to keep track of.
I'm not sure that I would agree here. Do you have a simple example?
7 replies →
Closures are an implementation technique and objects a semantics. To equate them is to confuse implementation and interface.
(Functions + tuples + recursion) is powerful enough to embed objects very nicely though!
You need a term to distinguish non closing over closing functions, hence the closure leakage. Or maybe HOF ?
Functions that don't "close over the environment" are ones that are defined in the null environment. Normally you have
But you could also have "bare functions" if you liked
This would force all names to be explicitly applied, I think.
2 replies →
hi tel, would you mind elaborating on what you mean by "objects [are] a semantics"?
A closure is a data structure commonly used to represent a first-class function (containing a function pointer for the code and some sort of structure mapping the environment's bound variables to their values). Implementing a language with first-class functions does not require using closures. You could have an interpreter that performs beta reduction on the syntax tree, and first-class functions would still behave the same way. So closures are an implementation detail.
In OOP, there are pieces of data that have operations associated with them. Two objects are free to have their own "version" of the same operation (same-named), and when you invoke it on an object, you get that object's version. In writing one of those operations, you have a handle on the thing you're operating on without having to take it as an argument. This specifies what result you'll compute and what side effects you'll cause by invoking an operation (i.e., the semantics). It does not specify things like where in program memory the code for that operation will live or how invoking it will work (implementation).
I like to see this as a sort of duality: closures are objects that have a single method (call) and objects are made of functions that can only capture one variable (this).
You can have as many methods as you like. Here's an example comparing one with the other in Golang: http://play.golang.org/p/TXZlZL7Tl8
That's not a closure. That's returning a struct. That struct is an object that has several instance members that are functions, which you've created as closures, but note you're still returning a struct. To return a closure, you need to return a function type, which then has exactly one way to call it, which is the claim here about functions.
Of course you can dispatch anything you like within that call, turning a closure back into "methods", although in most languages that's a fairly painful way to operate even though if it is possible. Personally over the years I've come more around to tel's point of view, which is that as related as objects and closures may be, they aren't quite just two sides of the same coin, as further evidenced by the fact that pretty much all modern OO languages also include closures. If they really were the same thing in two guises somebody would probably have fully unified them by now, but they aren't the same thing. As much fun as the koan is, I think it's false wisdom.
2 replies →
The spot I start to feel fuzzy, though, is if you start talking about higher-level abstractions. E.g, are interfaces equivalent to type classes?
You have to specify the language; there's no (useful) definition of type classes and interfaces outside of the context of a specific language that is specific enough to make reliable comparisons.
If you mean "Are Haskell type classes equivalent to Go interfaces?", the answer is no, Haskell type classes are substantially more powerful, even before you start turning on extensions. For instance, "Go" can not express the Monad typeclass at all.
2 replies →
As others have exemplified: it gets really hard to talk about this stuff outside of formal models. Especially if your goal is to talk about equivalency.
At this point I start trying to turn toward System F, but that's my hammer for this particular nail and I don't know an equivalent one in the object side of things. I'm certain you can express higher-level things in System F which are equivalent to interfaces. I know there's a translation of typeclasses to System F—it's called Haskell, har har—although you have to recognize that the "search" component of typeclasses will be lost.
Interfaces—at least in C#/Java—are equivalent to product types; they let you express the notion of conjunction within the type system.
Similarly, “implementation inheritance” (where every class is either sealed/final or abstract) is how we express sum types.
We can simulate type classes in C# by using implicit casts to abstract classes (interestingly, it’s not so straightforward to simulate the awesomeness of type classes in F#).
The key to all of this is to realize that “types” and “classes” are not equivalent, even though C# and Java conflate them.
Yes, it's not very formal and as others said it would need some definitions to make a useful result.
But actually I don't think that this duality is related to types: in a static language, the types of captured variables does not appear in a value's type. And for the object side, the type of instance variables is hidden behind the public interface too.
So it's really more about techniques for creating abstractions than how the values are composed together.
Depends if you have multiple inheritance.
A closure is 1 function and an environment. An object is N functions and an environment.
Objects are more useful as you don't need to repeat the environment to implement more than 1 operation.
Both objects and closures can be type erased so that the environment is not part of their type.
That single closure function could return e.g. a map containing more functions that share the same environment.
Conceptually they're both just a combination of some data and code that (usually) makes use of that data. I think a great example of this is function objects in C++.
Closures are used as objects quite a lot in R, as the standard structures are all actually immutable (to first order the only common user facing mutable things in R are variable bindings / environments, there are reference classes like RC and R6 but they are not considered core language). A lot of R users may not know this as value mutability is simulated through aggressive variable re-binding.
See Kiselyov fp-oo relation ML thread
http://okmij.org/ftp/Scheme/oop-in-fp.txt
Wouldn't closure be more like a single-method-objectin a class that has no class methods?
A clojure carries its own states (variables) that it, only, can modify. While the states (variables) of an object can be changed by another method for the same object, or by a class method, or even methods from another object if it uses method variables.
... but this would eliminate huge amounts of internet discussions. We better leave it as it is.