Facilitating the spread of knowledge and innovation in professional software development



Choose your language

InfoQ Homepage News C# Futures: Closure Annotations

C# Futures: Closure Annotations

Leia em PortuguÃªs



The proposal begins with capture lists, a concept seen in C++. Here is an example of a normal closure and one with a capture list:

var x = 100;
Func<int> a = () => x * 2;
Func<int> b = [x] () => x * 2;

If this syntax is used, any variable not in the capture list (denoted by brackets [x]) cannot be used inside the anonymous function without triggering a compiler error. If you use an empty list, [], then it will guarantee a closure won’t be created. This can help performance, as non-closure anonymous functions don’t require a memory allocation.

To access the current object from the closure, you would use [this]. This would reduce the occurrences of accidentally capturing the current object, which can lead to memory leaks.

Capturing by Value

There are times when you only need a copy of value inside the closure and don’t want to actually share a variable between the two. Under this proposal, you can indicate that using the capture list.

Func<int> c = [int xCopy = x]() => xCopy * 2;

This is very verbose, so alternatives are being suggested that would mean the same thing.

Func<int> d = [value x]() => x * 2; //this x is a copy
Func<int> e = [val x]() => x * 2; //this x is a copy
Func<int> f = [let x]() => x * 2; //this x is a copy
Func<int> g = [=x]() => x * 2; //this x is a copy

In order to make the normal by reference closure more explicit, this syntax was proposed:

Func<int> h = [ref x]() => x * 2; //x is an alias
Func<int> i = [&x]() => x * 2; //x is an alias

Related to this is the “skinny arrow” proposal. This would implicitly capture all variables by value.

Func<int> j = () -> x * 2; //this x is a copy

Weak Captures

As mentioned before, closures that outlast the function that creates them are a common source of memory leaks. So Miguel do Icaza suggested that weak references be included in the proposal. Stephen Toub offered this syntax for it:

Action k = [weak myObject] () => […]
Action l = [weak this] () => […]
Action m = [wro = new WeakReference(myObject)] () => […]


As mentioned in the introduction, this proposal is controversial. No matter which variants you choose, this new syntax add a lot of visual clutter to the code. And for shorter closures, it doesn’t add much information that you wouldn’t already have.

Adding the capture list has to be optional for backwards compatibility. Given how tedious it is, most developers will probably just not bother to type it, which would bring into doubt the usefulness of the feature at all.

Rate this Article


Hello stranger!


Get the most out of the InfoQ experience.


Community comments

  • Capture lists not necessary

    by Jules Jacobs,


    There is no reason to include a capture list since you can already see what is captured by looking at the code in the closure. Don't repeat yourself. The by value capture and weak reference capture could be done like so:

    const int xCopy = x;
    Func<int> f = () => xCopy * 2;

    var wro = new WeakReference(myObject);
    Func<int> f = () => ...;

  • Re: Capture lists not necessary

    by arnaud m,







Company name:
Company role:
Company size: