Dynamic closure vs static closure

KennyTM~ kennytm at gmail.com
Sat Oct 25 05:21:59 PDT 2008


Bill Baxter wrote:
> On Sat, Oct 25, 2008 at 6:30 PM, KennyTM~ <kennytm at gmail.com> wrote:
>> Frank Benoit wrote:
>>> It is great to hear that this issue is getting solved.
>>> How will be the now syntax?
>>>
>>> I wonder if the distinction between dynamic/static closure shall be done
>>> on the calling site, or the called site.
>>>
>>> void foo( void delegate() dg ){
>>> }
>>> // -or-
>>> void foo2( scope void delegate() dg ){
>>> }
>>>
>>> void bar(){
>>>  int i;
>>>  foo({
>>>    i++;
>>>  });
>>>  // -or-
>>>  foo( scope {
>>>    i++;
>>>  });
>>> }
>>>
>>> Because I think, the foo method/function signature has to define if the
>>> delegate is escaping or not. The caller might not know it.
>>>
>>> If the signature defines this, the compiler can check that and give more
>>> safety.
>> It should done on the calling site (the point where delegates are created).
>> Why the called function need to know if the delegate is a closure or not?
>> What they can do is just call the delegate.
> 
> The problem is this
> 
> {
>     float x = 3.14;
>     bar( float delegate (float y){ return x*y ; } );
>       // this delegate need to be allocated?
> }
> 
> If bar is going to hold onto the delegate beyond the end of the scope,
> then allocation is needed.  The author of bar() may be in a better
> position to judge that than the caller of bar().  But I'm not sure if
> that's the only kind of situation to be concerned about.  Are there
> other cases where only caller knows which it should be?
> 
> --bb

OK. Then both the call site and the function need the "scope", since the 
function signature alone is surely insufficient to determine if the 
delegate is closure or not.

Since filling the parameter is just a cloning process, this can be 
reduced to asking if

    <delegate-type> f = g;

will produce something weird, when one side is a closure, etc.

The simple solution is to make the delegates on stack a super type of 
delegates on heap.

(Don't mind the "static" keyword yet. I followed the name "static 
closure" described somewhere else. I agree "static" is too overloaded.)



--------

alias float delegate(in float) FloatDelegate;

// by default delegates are on heap for access safety.
FloatDelegate g, sin_pi;

// but I can declare it only needs to live on stack.
// i.e. the parameters won't jump out of its scope.
static(FloatDelegate) h;

// require allocation on heap. (right? right?)
void store (FloatDelegate f) {
   .g = f;
}

// don't require to allocation on heap
float evaluate_at (static(FloatDelegate) f, in float x) {
   return f(x);
}

// don't just deal with parameters... the return values need to be 
considered as well.
FloatDelegate square (FloatDelegate f) {
   return float delegate(in float x) { return f(x)*f(x); }
}
FloatDelegate plus_zero_of (static(FloatDelegate) f) {
   auto at_zero = f(0);
   return float delegate(in float x) { return x + at_zero; };
}
static(FloatDelegate) get_zero_function () {
   return static float delegate(in float) { return 0; };
}


{
   float pi = 3.1415926535f;
   // don't require allocation on heap.
   // I know this, therefore the static in front.
   auto cos_pi = static float delegate(in float y){ return cos(pi * y); };
   auto tan_pi = static float delegate(in float y){ return tan(pi * y); };

   // delegate on stack set to another delegate on stack: OK.
   writefln(evaluate_at(tan_pi, 0.2f));

   // require allocation on heap
   sin_pi = float delegate(float y) { return sin(pi * y); }

   // Oops, cos_pi is on stack, but the func sig requires on heap.
   // should generate error.
   //store(cos_pi);
}

// sin_pi already on heap, although the func sig said can be on stack.
// should _not_ generate error.
writefln(evaluate_at(sin_pi, 0.4f));

// g can now stay on stack, although its type is a closure.
g = get_zero_function();

// also ok.
h = get_zero_function();

// this should fail.
h = g;



More information about the Digitalmars-d mailing list