English 中文(简体)
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 expensive 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
", 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.





相关问题
What are the differences between NP, NP-Complete and NP-Hard?

What are the differences between NP, NP-Complete and NP-Hard? I am aware of many resources all over the web. I d like to read your explanations, and the reason is they might be different from what s ...

Implementation Detail for Graph Analysis Algorithms

Let s say I have a graph with "heavy" nodes, that is each node is an object that is already carrying a lot of data. I want to do a graph transformation that requires me to calculate a special ...

Worst case running time (Big O)

I have this question, and I don t know how to solve it, because I don t understand it. :( The question is: Programs A and B are analyzed and are found to have worst case running times no ...

RSA cryptosystem

Hi i am trying to set up an RSA cryptosystem i have all the values except d selected prime numbers: p=1889, q=2003, n=3783667, phi=3779776, e= 61 i got stuck finding d could anyone help me to figure ...

BNF Grammar Derivation

I want to apply rules of BNF Grammar to produce derivation for : a_Num

热门标签