Value closures (no GC allocation)

MakersF via Digitalmars-d digitalmars-d at puremagic.com
Mon May 29 14:26:11 PDT 2017


On Thursday, 25 May 2017 at 03:10:04 UTC, Adam D. Ruppe wrote:
> Snip

I think the discussion is going in two orthogonal directions, 
which are:

1) Capture by value. This is the ability to have a lambda which 
behaves as expected in the example Vittorio showed

>   void delegate()[] arr;
>
>    foreach(i; 0..5)
>    {
>        arr ~= () => writeln(i);
>    }
>
>    foreach(f; arr)
>    {
>        f();
>    }
>
>This is going to print "4 4 4 4"

2) Allocation of the lambda context. Whether this is performed by 
the GC, in the stack, or with another mechanism.

The reason these two points are orthogonal is that, as Adam 
showed, the ability to achieve one of the point is independent 
from the other (the capture by reference context allocation can 
be changed with the scope keyword, and from my understanding it's 
an implementation detail, it does not guarantee the use of the 
GC. And the value of capture by value could be allocated on the 
heap with the GC).


I see two weaknesses in this proposal:

1) The lambda is not compatible with a delegate anymore

2) There need to be a special notation for reference capture

Adam said
> I'm against that, no need adding it and it complicates the 
> whole thing. For example, "ref int _i;" as a struct member; 
> there's no such thing in D. (the compiler could do it but 
> still). And you'd have to explain the lifetime. Just no point 
> doing this, the current behavior is completely fine for this.



The other problem I see, which is easily noticeable when defining 
the new grammar, is that we are proposing a grammar which is a 
superset of the current one, but we are proposing it as an 
addition.


One of the assumption of D is that the GC is not a problem in the 
vast majority of the situations, and you want things to just work.
I think there is big value in the capture context not having to 
be explicit (even if usually I much prefer explicity over 
implicity).


Considered this, I'd propose an extension of the lambda syntax 
instead of an addition of a ValueFunctionLitteral.

Given the syntax
> [...] (...) ... {...}
which is composed of what I will call "capture", "parameters", 
"attributes", "body" (with capture and attributes optional)
the semantic would be:

- if no capture is provided the behavior is equivalent to today 
(automatic capturing by reference in a context allocated however 
the compiler prefers). This provides full backward compatibility.
Example
(int i) { writeln(i + j);}

j is captured by reference in a context allocated (possibly) on 
the GC. This is compatible with a delegate void(int).


- if capture is provided, then the lambda is rewritten as a 
struct, which the explicit variables in the capture list being 
captured by value, and the remaining being captured by reference 
(so there would still be implicit capture, which is considered 
convenient in many programming languages).
This is potentially unsafe since a reference could be copied when 
copying the struct, and the struct might outlive the referred 
object.
Example
[x] (int i) { writeln(i + j + x);}

x is captured by value in a local struct.
j is captured by reference in a local struct.
This is not a delegate anymore (different ABI).


- if "delegate" is used, then the capture context is allocated 
however the compile prefers

[x] delegate (int i) { writeln(i + j + x);}

x is captured by value in a (possibly) GC context.
j is captured by reference in a (possibly) GC context.
This is a delegate (compatible ABI).


This thus is an extension of the lambda syntax to allow capturing 
by value, but maintaining all the current properties and 
providing a way to remain compatible with the delegate functions.
You can also use the @nogc attribute to verify that the GC is not 
used (and in case also "delegate" is used "scope" will need to be 
used so that the compiler does not require the GC).

What are your opinions?
Please state if there are some misconceptions on the current 
situation.


More information about the Digitalmars-d mailing list