Dynamic closure vs static closure

KennyTM~ kennytm at gmail.com
Mon Oct 27 03:51:16 PDT 2008


Yigal Chripun wrote:
> Jarrett Billingsley wrote:
>> On Sat, Oct 25, 2008 at 5:08 PM, Yigal Chripun <yigal100 at gmail.com> wrote:
>>> Jarrett Billingsley wrote:
>>>> On Sat, Oct 25, 2008 at 9:30 AM, Yigal Chripun <yigal100 at gmail.com> wrote:
>>>>> anyway, I think you got my intention by now.
>>>>> I really don't want to have 3 kinds of function types. I think the
>>>>> already existing separation between function pointers and delegates
>>>>> could be handled better by adding an implicit cast.
>>>> It would start to become untenable, but I would imagine closures would
>>>> be implicitly convertible to scope delegates, since in effect they are
>>>> a subtype, and anywhere a scope delegate could be used, a closure
>>>> could be used as well.  Add to that implicit conversion from functions
>>>> to delegates using thunks and bam, you could have a function take one
>>>> type and it could accept all three.
>>> OK, But my question is why do you need that separation in the first
>>> place? to me it seems an unnecessary distinction between scope delegates
>>> and "regular" delegates.
>> Did you see the thread on performance?
>>
> 
> I've read that thread and understand the benefits of D1 style delegates,
> performance wise. What I meant to say was Why do we need two separate
> *types* for that?
> both styles can be used with one type and with a scope modifier as I
> replied to Kenny.
> 
>> -- snip --

The scope solution is very good since whether the frame is allocated on 
heap or on stack is determined only at the point of declaring the DG. 
After the declaration a closure is no different from a delegate -- both 
has the same structure {ptr, funcptr} and even the calling convention is 
the same. The two are indistinguishable after declaration.

But you'll need two types if you want to distinguish them. Such as to 
enforce a non-scope constraint:

   // f1's ptr can be on stack or on heap.
   void T1 (scope delegate f1) { ... }

   // f2's ptr must be on heap.
   void T2 (delegate f2) { ... }

   ...
   {
     ...
     scope f4 = delegate { ... }; // frame allocated on stack.
     ...
     {
        ...
        T2(f4);
        //  T2: Hi, f4, is your .ptr on stack or on heap?
        //      For safety, only (.ptr)s on heap are allowed.
        //  f4: I... don't know. Just let me in? I'll behave.
        ...

     }
   }
   ...

   // later on an access violation/stack overflow appears mysteriously.

Solutions I can think of :-
  (a) Use some algorithm to check if the .ptr is on heap or on stack 
(indeed the address for them are significantly different);
  (b) Add a field to indicate if f4 is allocated on stack or on heap;
  (c) The “scope” keyword for delegates do nothing, let the programmer 
take the risk (current behavior);
  (d) Automatically .dup the frame when a delegate is passed into an 
argument without “scope”.

Problems for each solution :-
  (a) is probably not reliable (is it? can the GC help?), and DG & CL 
now behaves like 2 different types.
  (b) is effectively adding a new type.
  (c) is probably unsafe.
  (d) is slow.

The move I'd take for now would be (c) if no new types are wanted, 
because it's the current behavior and if you want significant 
performance out of nowhere there should be some risk trade off. The most 
urgent issue it seems right now is to restore the performance of 
delegates to D1 level.

If (a) can be done reliably and quickly than I vote for (a).

There could be other solutions as well I don't know yet.



More information about the Digitalmars-d mailing list