Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the exact definition of a closure?

I've read through previous topics on closures on stackflow and other sources and one thing is still confusing me. From what I've been able to piece together technically a closure is simply the set of data containing the code of a function and the value of bound variables in that function.

In other words technically the following C function should be a closure from my understanding:

int count()
{
    static int x = 0;

    return x++;
}

Yet everything I read seems to imply closures must somehow involve passing functions as first class objects. In addition it usually seems to be implied that closures are not part of procedural programming. Is this a case of a solution being overly associated with the problem it solves or am I misunderstanding the exact definition?

like image 791
Amaron Avatar asked Jul 08 '09 01:07

Amaron


People also ask

Is closure the same as closing?

Closure indicates one complete instance of the action of the verb to close. Closing indicates the action of the verb to close that was uncompleted, or still in progress, at the time referred to.

What does closure consist of?

Closure refers to having a sense of understanding, peace, and accepted finality of the relationship whether it's ended because of loss, rejection, or growing apart.

What is the best definition of closure quizlet?

A self-contained block of functionality that can be passed around and used in your code.


2 Answers

No, that's not a closure. Your example is simply a function that returns the result of incrementing a static variable.

Here's how a closure would work:

function makeCounter( int x )
{
  return int counter() {
    return x++;
  }
}

c = makeCounter( 3 );
printf( "%d" c() ); => 4
printf( "%d" c() ); => 5
d = makeCounter( 0 );
printf( "%d" d() ); => 1
printf( "%d" c() ); => 6

In other words, different invocations of makeCounter() produce different functions with their own binding of variables in their lexical environment that they have "closed over".

Edit: I think examples like this make closures easier to understand than definitions, but if you want a definition I'd say, "A closure is a combination of a function and an environment. The environment contains the variables that are defined in the function as well as those that are visible to the function when it was created. These variables must remain available to the function as long as the function exists."

like image 198
Peter Eddy Avatar answered Oct 04 '22 12:10

Peter Eddy


For the exact definition, I suggest looking at its Wikipedia entry. It's especially good. I just want to clarify it with an example.

Assume this C# code snippet (that's supposed to perform an AND search in a list):

List<string> list = new List<string> { "hello world", "goodbye world" };
IEnumerable<string> filteredList = list;
var keywords = new [] { "hello", "world" };
foreach (var keyword in keywords)
    filteredList = filteredList.Where(item => item.Contains(keyword));

foreach (var s in filteredList)  // closure is called here
    Console.WriteLine(s);

It's a common pitfall in C# to do something like that. If you look at the lambda expression inside Where, you'll see that it defines a function that it's behavior depends on the value of a variable at its definition site. It's like passing a variable itself to the function, rather than the value of that variable. Effectively, when this closure is called, it retrieves the value of keyword variable at that time. The result of this sample is very interesting. It prints out both "hello world" and "goodbye world", which is not what we wanted. What happened? As I said above, the function we declared with the lambda expression is a closure over keyword variable so this is what happens:

filteredList = filteredList.Where(item => item.Contains(keyword))
                           .Where(item => item.Contains(keyword)); 

and at the time of closure execution, keyword has the value "world," so we're basically filtering the list a couple times with the same keyword. The solution is:

foreach (var keyword in keywords) {
    var temporaryVariable = keyword;
    filteredList = filteredList.Where(item => item.Contains(temporaryVariable));
}

Since temporaryVariable is scoped to the body of the foreach loop, in every iteration, it is a different variable. In effect, each closure will bind to a distinct variable (those are different instances of temporaryVariable at each iteration). This time, it'll give the correct results ("hello world"):

filteredList = filteredList.Where(item => item.Contains(temporaryVariable_1))
                           .Where(item => item.Contains(temporaryVariable_2));

in which temporaryVariable_1 has the value of "hello" and temporaryVariable_2 has the value "world" at the time of closure execution.

Note that the closures have caused an extension to the lifetime of variables (their life were supposed to end after each iteration of the loop). This is also an important side effect of closures.

like image 33
mmx Avatar answered Oct 04 '22 14:10

mmx