What are 'closures' in .NET?
Asked Answered
L

12

222

What is a closure? Do we have them in .NET?

If they do exist in .NET, could you please provide a code snippet (preferably in C#) explaining it?

Legator answered 9/1, 2009 at 16:1 Comment(0)
S
296

I have an article on this very topic. (It has lots of examples.)

In essence, a closure is a block of code which can be executed at a later time, but which maintains the environment in which it was first created - i.e. it can still use the local variables etc of the method which created it, even after that method has finished executing.

The general feature of closures is implemented in C# by anonymous methods and lambda expressions.

Here's an example using an anonymous method:

using System;

class Test
{
    static void Main()
    {
        Action action = CreateAction();
        action();
        action();
    }

    static Action CreateAction()
    {
        int counter = 0;
        return delegate
        {
            // Yes, it could be done in one statement; 
            // but it is clearer like this.
            counter++;
            Console.WriteLine("counter={0}", counter);
        };
    }
}

Output:

counter=1
counter=2

Here we can see that the action returned by CreateAction still has access to the counter variable, and can indeed increment it, even though CreateAction itself has finished.

Soprano answered 9/1, 2009 at 16:4 Comment(18)
Yeah, I was just thinking that (although the article has lots of them in.)Soprano
Yeah, but it helps to include one here, so that in case your link ever gets stale (heaven forbid), your post here still has some info.Aware
Thanks Jon. BTW, is there something that you don't know in .NET? :) Who do you go to when you have questions?Legator
There's always more to learn :) I've just finished reading CLR via C# - very informative. Other than that, I usually ask Marc Gravell for WCF/binding/expression trees, and Eric Lippert for C# language things.Soprano
To say a closure is "a block of code" isn't technically correct; it has to do with scope hanging around after it was originally defined. A "block of code" is a means to obtaining a closure, but not technically a closure.Aware
I've got the scope part later in the sentence. You could arguably use the word "function" instead of "block of code" but I think the scope part is covered.Soprano
I noticed that, but I still think your statement about it being "a block of code which can be executed at a later time" is simply incorrect - it has nothing to do with execution, more to do with variable values and the scope than execution, per se.Aware
I'd say that closures aren't useful unless they can be executed, and the "at a later time" highlights the "oddness" of being able to capture the environment (which might otherwise have gone away by execution time). If you only quote half the sentence then it's an incomplete answer, of course.Soprano
Something to add, the closure is stored as a reference, even though it's a value type. You'll see this if you play around with functions that return functions :)Fatuous
@SLC: What do you mean by "it's a value type"? int is a value type, but that's not the closure.Soprano
I thought the delegate closed over counter, such that when you call the delegate via action(), counter is available to be incremented even though it's outside the scope of the delegate.Fatuous
@SLC: Yes, counter is available to be incremented - the compiler generates a class which contains a counter field, and any code referring to counter ends up going through an instance of that class.Soprano
@JonSkeet since int is a value type, int x = 3; int y = x; doesn't result in any references being made, x and y are independent. But with counter, the compiler presumably does something because you can make counter a static int, and change it between the two action() calls to be 50, and the second action() call will output 51. So the delegate must have a reference to counter, which means counter can't be a value type. Does that make sense?Fatuous
@SLC: In the example I've given, it's a local variable in the source code - but as I say, the compiler creates an instance of a class which contains a field. counter itself is still stored in a value type, but it's stored in an instance of a class. I suggest you compile the above code and then look at it in Reflector with no optimizations :)Soprano
John said that "the compiler generates a class which contains a counter field" and this was key thing for me in order to understand. The comment is not up voted enough in my opinion, anyway thanks a lot for this very interesting discussion.Parse
It's fine and dandy but I'm having trouble seeing the the practical use for this. Real world applications. It's pretty easy to implement a counter without using a closure. Maybe I'm missing something.Cahier
@RayLoveless: Did you read the linked article at the top of the answer? There are plenty of examples there. If you've ever used LINQ in C#, that's another prime example...Soprano
a closure sounds like a delegate function. The delegate function can be executed at a later timeDearman
V
28

If you are interested in seeing how C# implements Closure read "I know the answer (its 42) blog"

The compiler generates a class in the background to encapsulate the anoymous method and the variable j

[CompilerGenerated]
private sealed class <>c__DisplayClass2
{
    public <>c__DisplayClass2();
    public void <fillFunc>b__0()
    {
       Console.Write("{0} ", this.j);
    }
    public int j;
}

for the function:

static void fillFunc(int count) {
    for (int i = 0; i < count; i++)
    {
        int j = i;
        funcArr[i] = delegate()
                     {
                         Console.Write("{0} ", j);
                     };
    } 
}

Turning it into:

private static void fillFunc(int count)
{
    for (int i = 0; i < count; i++)
    {
        Program.<>c__DisplayClass1 class1 = new Program.<>c__DisplayClass1();
        class1.j = i;
        Program.funcArr[i] = new Func(class1.<fillFunc>b__0);
    }
}
Verified answered 22/8, 2011 at 3:47 Comment(4)
Hi, Daniil - You answer is very useful and i wanted to go beyond your answer and follow up but the link is broken. Unfortunately, my googlefu isn't good enough to find where it moved to.Latrena
I've found mirror to mentioned article at blog.bonggeek.com/2006/07/…Apartheid
"I know the answer (its 42) blog" url doesn't workEntelechy
@DanilaPolevshchikov that link doesn't appear to explain the implementation (as this answer does), only the feature.Ceballos
B
12

Closures are functional values that hold onto variable values from their original scope. C# can use them in the form of anonymous delegates.

For a very simple example, take this C# code:

delegate int testDel();

static void Main(string[] args)
{
    int foo = 4;
    testDel myClosure = delegate()
    {
        return foo;
    };
    int bar = myClosure();
}

At the end of it, bar will be set to 4, and the myClosure delegate can be passed around to be used elsewhere in the program.

Closures can be used for a lot of useful things, like delayed execution or to simplify interfaces - LINQ is mainly built using closures. The most immediate way it comes in handy for most developers is adding event handlers to dynamically created controls - you can use closures to add behavior when the control is instantiated, rather than storing data elsewhere.

Better answered 9/1, 2009 at 16:4 Comment(0)
P
10
Func<int, int> GetMultiplier(int a)
{
     return delegate(int b) { return a * b; } ;
}
//...
var fn2 = GetMultiplier(2);
var fn3 = GetMultiplier(3);
Console.WriteLine(fn2(2));  //outputs 4
Console.WriteLine(fn2(3));  //outputs 6
Console.WriteLine(fn3(2));  //outputs 6
Console.WriteLine(fn3(3));  //outputs 9

A closure is an anonymous function passed outside of the function in which it is created. It maintains any variables from the function in which it is created that it uses.

Pneumoencephalogram answered 9/1, 2009 at 16:9 Comment(0)
A
4

Here is a contrived example for C# which I created from similar code in JavaScript:

public delegate T Iterator<T>() where T : class;

public Iterator<T> CreateIterator<T>(IList<T> x) where T : class
{
    var i = 0; 
    return delegate { return (i < x.Count) ? x[i++] : null; };
}

So, here is some code that shows how to use the above code...

var iterator = CreateIterator(new string[3] { "Foo", "Bar", "Baz"});

// So, although CreateIterator() has been called and returned, the variable 
// "i" within CreateIterator() will live on because of a closure created 
// within that method, so that every time the anonymous delegate returned 
// from it is called (by calling iterator()) it's value will increment.

string currentString;    
currentString = iterator(); // currentString is now "Foo"
currentString = iterator(); // currentString is now "Bar"
currentString = iterator(); // currentString is now "Baz"
currentString = iterator(); // currentString is now null

Hope that is somewhat helpful.

Aware answered 9/1, 2009 at 16:12 Comment(1)
You've given an example, but didn't offer a general definition. I gather from your comments here that they are 'more about scope', but surely there's more to it than that?Flannel
B
4

A closure is when a function is defined inside another function (or method) and it uses the variables from the parent method. This use of variables which are located in a method and wrapped in a function defined within it, is called a closure.

Mark Seemann has some interesting examples of closures in his blog post where he does a parallel between oop and functional programming.

And to make it more detailed

var workingDirectory = new DirectoryInfo(Environment.CurrentDirectory);//when this variable
Func<int, string> read = id =>
    {
        var path = Path.Combine(workingDirectory.FullName, id + ".txt");//is used inside this function
        return File.ReadAllText(path);
    };//the entire process is called a closure.
Browse answered 16/8, 2016 at 15:26 Comment(0)
A
3

Closures are chunks of code that reference a variable outside themselves, (from below them on the stack), that might be called or executed later, (like when an event or delegate is defined, and could get called at some indefinite future point in time)... Because the outside variable that the chunk of code references may gone out of scope (and would otherwise have been lost), the fact that it is referenced by the chunk of code (called a closure) tells the runtime to "hold" that variable in scope until it is no longer needed by the closure chunk of code...

Afreet answered 9/1, 2009 at 16:9 Comment(4)
As I indicated on someone else's explanation: I hate to be technical, but closure has more to do with scope - a closure can be created in a couple of different ways, but a closure isn't the means, it is the end.Aware
Closures are relatively new to me, so it's entirely possible I misunderstand, but I get the scope part.. My answer is focused around scope. So I am missing what yr comment is trying to correct... What else can scope be relevant to but some chunk of code? (function, anonymous method, or whatever)Afreet
Isn't the key to a closure that some "chunk of runnable code" can access a variable or in-memory value that it syntactically "outside" of it's scope, after that variable should have ordinarily gone "out of scope" or been destroyed?Afreet
And @Jason, no worries about being technical, this closure idea is something I took a while to get my head wrapped around, in long discussions with a co-worker, about javascript closures... but he was a Lisp nut and I never quite got through the abstractions in his explanations...Afreet
C
2

Basically closure is a block of code that you can pass as an argument to a function. C# supports closures in form of anonymous delegates.

Here is a simple example:
List.Find method can accept and execute piece of code (closure) to find list's item.

// Passing a block of code as a function argument
List<int> ints = new List<int> {1, 2, 3};
ints.Find(delegate(int value) { return value == 1; });

Using C#3.0 syntax we can write this as:

ints.Find(value => value == 1);
Cantle answered 9/1, 2009 at 16:13 Comment(1)
I hate to be technical, but closure has more to do with scope - a closure can be created in a couple of different ways, but a closure isn't the means, it is the end.Aware
B
2

If you write an inline anonymous method (C#2) or (preferably) a Lambda expression (C#3+), an actual method is still being created. If that code is using an outer-scope local variable - you still need to pass that variable to the method somehow.

e.g. take this Linq Where clause (which is a simple extension method which passes a lambda expression):

var i = 0;
var items = new List<string>
{
    "Hello","World"
};   
var filtered = items.Where(x =>
// this is a predicate, i.e. a Func<T, bool> written as a lambda expression
// which is still a method actually being created for you in compile time 
{
    i++;
    return true;
});

if you want to use i in that lambda expression, you have to pass it to that created method.

So the first question that arises is: should it be passed by value or reference?

Pass by reference is (I guess) more preferable as you get read/write access to that variable (and this is what C# does; I guess the team in Microsoft weighed the pros and cons and went with by-reference; According to Jon Skeet's article, Java went with by-value).

But then another question arises: Where to allocate that i?

Should it actually/naturally be allocated on the stack? Well, if you allocate it on the stack and pass it by reference, there can be situations where it outlives it's own stack frame. Take this example:

static void Main(string[] args)
{
    Outlive();
    var list = whereItems.ToList();
    Console.ReadLine();
}

static IEnumerable<string> whereItems;

static void Outlive()
{
    var i = 0;
    var items = new List<string>
    {
        "Hello","World"
    };            
    whereItems = items.Where(x =>
    {
        i++;
        Console.WriteLine(i);
        return true;
    });            
}

The lambda expression (in the Where clause) again creates a method which refers to an i. If i is allocated on the stack of Outlive, then by the time you enumerate the whereItems, the i used in the generated method will point to the i of Outlive, i.e. to a place in the stack that is no longer accessible.

Ok, so we need it on the heap then.

So what the C# compiler does to support this inline anonymous/lambda, is use what is called "Closures": It creates a class on the Heap called (rather poorly) DisplayClass which has a field containing the i, and the Function that actually uses it.

Something that would be equivalent to this (you can see the IL generated using ILSpy or ILDASM):

class <>c_DisplayClass1
{
    public int i;

    public bool <GetFunc>b__0()
    {
        this.i++;
        Console.WriteLine(i);
        return true;
    }
}

It instantiates that class in your local scope, and replaces any code relating to i or the lambda expression with that closure instance. So - anytime you are using the i in your "local scope" code where i was defined, you are actually using that DisplayClass instance field.

So if I would change the "local" i in the main method, it will actually change _DisplayClass.i ;

i.e.

var i = 0;
var items = new List<string>
{
    "Hello","World"
};  
var filtered = items.Where(x =>
{
    i++;
    return true;
});
filtered.ToList(); // will enumerate filtered, i = 2
i = 10;            // i will be overwriten with 10
filtered.ToList(); // will enumerate filtered again, i = 12
Console.WriteLine(i); // should print out 12

it will print out 12, as "i = 10" goes to that dispalyclass field and changes it just before the 2nd enumeration.

A good source on the topic is this Bart De Smet Pluralsight module (requires registration) (also ignore his erroneous use of the term "Hoisting" - what (I think) he means is that the local variable (i.e. i) is changed to refer to the the new DisplayClass field).


In other news, there seems to be some misconception that "Closures" are related to loops - as I understand "Closures" are NOT a concept related to loops, but rather to anonymous methods / lambda expressions use of local scoped variables - although some trick questions use loops to demonstrate it.

Baskett answered 13/6, 2018 at 11:6 Comment(0)
M
0

Just out of the blue,a simple and more understanding answer from the book C# 7.0 nutshell.

Pre-requisit you should know :A lambda expression can reference the local variables and parameters of the method in which it’s defined (outer variables).

static void Main()
{
    int factor = 2;
   //Here factor is the variable that takes part in lambda expression.
    Func<int, int> multiplier = n => n * factor;
    Console.WriteLine (multiplier (3)); // 6
}

Real part:Outer variables referenced by a lambda expression are called captured variables. A lambda expression that captures variables is called a closure.

Last Point to be noted:Captured variables are evaluated when the delegate is actually invoked, not when the variables were captured:

int factor = 2;
Func<int, int> multiplier = n => n * factor;
factor = 10;
Console.WriteLine (multiplier (3)); // 30
Maser answered 23/12, 2017 at 5:49 Comment(0)
N
0

A closure aims to simplify functional thinking, and it allows the runtime to manage state, releasing extra complexity for the developer. A closure is a first-class function with free variables that are bound in the lexical environment. Behind these buzzwords hides a simple concept: closures are a more convenient way to give functions access to local state and to pass data into background operations. They are special functions that carry an implicit binding to all the nonlocal variables (also called free variables or up-values) referenced. Moreover, a closure allows a function to access one or more nonlocal variables even when invoked outside its immediate lexical scope, and the body of this special function can transport these free variables as a single entity, defined in its enclosing scope. More importantly, a closure encapsulates behavior and passes it around like any other object, granting access to the context in which the closure was created, reading, and updating these values.

enter image description here

Norvell answered 20/10, 2020 at 7:53 Comment(0)
B
-1

A closure is a function, defined within a function, that can access the local variables of it as well as its parent.

public string GetByName(string name)
{
    List<things> theThings = new List<things>();
    return  theThings.Find<things>(t => t.Name == name)[0];
}

so the function inside the find method.

t => t.Name == name

can access the variables inside its scope, t, and the variable name which is in its parents scope. Even though it is executed by the find method as a delegate, from another scope all together.

Bagnio answered 9/1, 2009 at 16:9 Comment(1)
A closure isn't a function, per se, it is more defined by talking about scope than functions. Functions merely assist in keeping the scope around, which causes a closure to be created. But to say a closure is a function isn't technically correct. Sorry to nitpick. :)Aware

© 2022 - 2024 — McMap. All rights reserved.