Exactly what is the difference between a "closure" and a "block"?
I've found that lots of people use the words closure and block interchangeably. Most of these people can't explain what they're talking about.
Some Java programmers (even ones from really e开发者_StackOverflow社区xpensive consultancies) talk about anonymous inner classes as "blocks" and "closures" - but I know this isn't true. (You can't pass mutable variables in from the scope of the method in which they're defined...)
I'm looking for:
- a precise, computer science definition of a block
- a precise, computer science definition of a closure
- and clarification on the difference between the two.
I'd really like to see links, articles or book references on these please.
While a block is just a piece of code that can be composed by statements and declarations but nothing else, a closure is a real first-class object, a real variable that has a block as its value.
The main difference is that a block simply groups instructions together (for example the body of a while statement), while a closure is a variable that contains some code that can be executed.
If you have a closure usually you can pass it as a parameter to functions, currify and decurrify it, and mainly call it!
Closure c = { println 'Hello!' }
/* now you have an object that contains code */
c.call()
Of course closures are more powerful, they are variables and can be used to define custom behaviour of objects (while usually you had to use interfaces or other OOP approaches in programming).
You can think of a closure as a function that contains what that function does inside itself.
Blocks are useful because they allow scoping of variables. Usually when you define a variable inside a scope you can override the outer definitions without any problems and new definitions will exist just during the execution of block.
for (int i = 0; i < 10; ++i)
{
int t = i*2;
printf("%d\r\n", t);
}
t
is defined inside the block (the body of the for
statement) and will last just inside that block.
A block is something syntactical - A logical unit of statements (more related to scope than to closure).
if (Condition) {
// Block here
}
else {
// Another block
}
A closure is related to anoymous functions or classes - An anonymous (function) object, a piece of code that is bound to an environment (with its variables).
def foo() {
var x = 0
return () => { x += 1; return x }
}
Here foo
returns a closure! The local variable x
persists through the closure even after foo
terminated and can be incremented through calls of the returned anonymous function.
val counter = foo()
print counter() // Returns 2
print counter() // Return 3
Note that's just Ruby in which block and closure are treated similarly since what Ruby calls block is a closure:
(1..10).each do |x|
p x
end
There each
-method is passed a closure function (taking a parameter x) which is called a block in Ruby.
There's a lot of confusion around here because there are terms with multiple definitions, and multiple distinct things that get conflated simply because they're usually found together.
First, we have "block". That's just a lexical chunk of code that makes a unit - the body of a loop, for instance. If the language actually has block scope, then variables can be defined that only exist within that chunk of code.
Second, we have callable code as a value type. In functional languages, these are function values - sometimes called "funs", "anonymous functions" (because the function is found in the value, not the name its assigned to; you don't need a name to call them), or "lambdas" (from the operator used to create them in Church's Lambda Calculus). They may be called "closures", but they aren't automatically true closures; in order to qualify, they must encapsulate ("close over") the lexical scope surrounding their creation - that is, variables defined outside the scope of the function itself but within the scope of its definition are still available whenever the function is called, even if the calling point is after the referenced variable would otherwise have gone out of scope and had its storage recycled.
For example, consider this Javascript:
function makeClosure() {
var x = "Remember me!";
return function() {
return "x='" + x + "'";
}
}
// console.log(x);
// The above is an error; x is undefined
var f = makeClosure();
console.log(f());
// The above outputs a string that includes x as it existed when f was created.
The variable x
is defined only within the body of the function makeClosure
; outside of that definition, it doesn't exist. After we call makeClosure
, the x
declared inside it should be gone. And it is, from the point of view of most of the code. But the function returned by makeClosure
was declared while x
existed, so it still has access to it when you call it later. That makes it a true closure.
You can have function values that are not closures, because they don't preserve scope. You can also have partial closures; PHP's function values only preserve specific variables that must be listed at the time the value is created.
You can also have callable code values that don't represent whole functions at all. Smalltalk calls these "block closures", while Ruby calls them "procs", though many Rubyists just call them "blocks", because they're the reified version of what's created by the {
...}
or do
...end
syntax. What makes them distinct from lambdas (or "function closures") is that they do not introduce a new call level. If the code in the body of a block closure invokes return
, it returns from the outer function/method the block closure exists within, not just the block itself.
That behavior is critical to preserving what R.D. Tennent labeled the "correspondence principle", which states that you should be able to replace any code with an inline function containing that code in the body and called immediately. For instance, in Javascript, you can replace this:
x=2
console.log(x)
with this:
(function(){x = 2;})();
console.log(x)
That example is not very interesting, but the ability to do this sort of transformation without affecting the behavior of the program plays a key role in functional refactoring. But with lambdas, as soon as you have embedded return
statements, the principle no longer holds:
function foo1() {
if (1) {
return;
}
console.log("foo1: This should never run.")
}
foo1()
function foo2() {
if (1) {
(function() { return; })();
}
console.log("foo2: This should never run.")
}
foo2()
The second function is different from the first; the console.log
is executed, because the return
only returns from the anonymous function, not from foo2
. This breaks the correspondence principle.
This is why Ruby has both procs and lambdas, even though the distinction is a perennial source of confusion for newbies. Both procs and lambdas are objects of class Proc
, but they behave differently, as indicated above: a return
just returns from the body of a lambda, but it returns from the method surrounding a proc.
def test
p = proc do return 1 end
l = lambda do return 1 end
r = l[]
puts "Called l, got #{r}, still here."
r = p[]
puts "Called p, got #{r}, still here?"
end
The above test
method will never get to the second puts
, because the invocation of p
will cause test
to return immediately (with a return value of 1). If Javascript had block closures, you could do the same thing, but it doesn't (although there is a proposal to add them).
The loud, bearded one has this to say about Closures and Blocks:
http://martinfowler.com/bliki/Closure.html
At one point he says a closure is a block that can be passed as an argument to a method.
The terms you are using are most commonly used together these days in Ruby, although the constructs previously appeared in Algol, Smalltalk, and Scheme. I would quote the Ruby standard, if there was one.
I'm not sure I'm able to answer your exact question, but I can illustrate. My apologies if you know this already...
def f &x
yield
x
end
def g
y = "block"
t = f { p "I'm a #{y}" }
y = "closure"
t
end
t = g
t.call
And...
$ ruby exam.rb
"I'm a block"
"I'm a closure"
$
So a block is an anonymous function-like sequence of code attached to a method call. It's used all over the Ruby API. When you make it easy enough to create an anonymous function it turns out they are useful for all kinds of things.
But note that after f
returns, then g
returns, we held on to the block by returning it from f
(as x
) and then from g
(as t
). Now we call the block a second time. Again, note that g()
has returned. But the block refers to a local variable in a function instance (and scope) that doesn't exist any more?! And it gets the new value of y
?!
So a closure is a function-like object that is closed over its lexical scope. They are quite challenging to implement because they destroy the do-it-with-a-stack model that is so useful for local variables in function call instances.
1. Ruby has various flavors of closure-like function objects; this is just one of them.
5
That's an integer.
Int workDaysInAWeek = 5
That's an integer variable and it may be set to a different integer. (If circumstances prevent you from modifying that value, it may be called a constant.)
Whereas the above concern numbers, blocks and closures concern algorithms. The distinction between blocks and closures, respectively, is also equivalent to the above.
精彩评论