July 22, 2004
Sean Kelly wrote:
> # void func()
> # {
> #    void d1() { ... }
> #    auto void d2() { ... }
> # }
> 
> In the above code, d1 will get a copy of the stack frame that it can carry
> outside of func, while d2 will not since it is declared as "auto."  This seems
> consistent with the existing auto semantics for variables.  Only catch is that,
> as you said, I think the default behavior should remain how it is.

Ok, I see what you're saying.  The syntax makes a lot of sense, except that I would prefer not to overload the "auto" keyword.  Maybe I'm the only one, but it didn't make immediate sense to me.  Remember how the keyword "static" got overloaded in C...ick.

How would you declare a delegate literal using the above syntax, however?  Would you declare
  void delegate() foo = auto delegate void() {...}
?

Ok, weird ponder here.  I've been playing with the idea that it would be nice to declare a delegate that has any arbitrary 'this' pointer, using the following syntax:
  MyClass foo = <whatever>;
  void delegate() del = foo.delegate void() { foo.x(); foo.y(); }

The cool thing is, I just realized that that syntax makes stack duplicates easier to create:
  void foo() {
    void delegate() del = stack_frame.dup.delegate void() { ... }
  }

Then, you realize that the current stack delegate syntax can be viewed as syntax sugar:
  void bar() {
    void delegate() d1 = delegate void() {...}
    void delegate() d2 = stack_frame.delegate void() {...}
  }
In the code above, both delegate literals are non-copying delegates.



Thoughts?

July 22, 2004
Russ Lewis wrote:
> Sean Kelly wrote:
> 
>> # void func()
>> # {
>> #    void d1() { ... }
>> #    auto void d2() { ... }
>> # }
>>
>> In the above code, d1 will get a copy of the stack frame that it can carry
>> outside of func, while d2 will not since it is declared as "auto."  This seems
>> consistent with the existing auto semantics for variables.  Only catch is that,
>> as you said, I think the default behavior should remain how it is.
> 
> 
> Ok, I see what you're saying.  The syntax makes a lot of sense, except that I would prefer not to overload the "auto" keyword.  Maybe I'm the only one, but it didn't make immediate sense to me.  Remember how the keyword "static" got overloaded in C...ick.
> 
> How would you declare a delegate literal using the above syntax, however?  Would you declare
>   void delegate() foo = auto delegate void() {...}
> ?
> 
> Ok, weird ponder here.  I've been playing with the idea that it would be nice to declare a delegate that has any arbitrary 'this' pointer, using the following syntax:
>   MyClass foo = <whatever>;
>   void delegate() del = foo.delegate void() { foo.x(); foo.y(); }
> 
> The cool thing is, I just realized that that syntax makes stack duplicates easier to create:
>   void foo() {
>     void delegate() del = stack_frame.dup.delegate void() { ... }
>   }
> 
> Then, you realize that the current stack delegate syntax can be viewed as syntax sugar:
>   void bar() {
>     void delegate() d1 = delegate void() {...}
>     void delegate() d2 = stack_frame.delegate void() {...}
>   }
> In the code above, both delegate literals are non-copying delegates.
> 
> 
> 
> Thoughts?
> 
Interesting.

I think you could almost make this work with templates alone(using a class and opCmd) if function themselves had a *.size* property to reveal the amount of stack space needed for the functions variables.  On first call of the function the space is allocated/initialized, with subsequent calls just referring to the stack frame.

I know the behavior I would like to use delegates for: like that in lua/scheme/Javascript (true closures).  It is just a hard feature to add with C because functions are not created, just declared.  When you specify 'static int a' within a inner function, static really means 'singular' because no matter where it is accessed, there is only one.

If delegates were forced to be created like other objects, implementing the underlying semantics would probably be very simple.

July 22, 2004
In article <cdp2td$10ib$1@digitaldaemon.com>, Russ Lewis says...
>
>How would you declare a delegate literal using the above syntax, however?  Would you declare
>   void delegate() foo = auto delegate void() {...}

Yeah I suppose.  And this does look a tad weird.

>Ok, weird ponder here.  I've been playing with the idea that it would be nice to declare a delegate that has any arbitrary 'this' pointer, using the following syntax:
>   MyClass foo = <whatever>;
>   void delegate() del = foo.delegate void() { foo.x(); foo.y(); }

Interesting idea.  The only weird thing here is that this feature would enable a user to break encapsulation rules by accessing hidden members via these delegates.

>Then, you realize that the current stack delegate syntax can be viewed as syntax sugar:
>   void bar() {
>     void delegate() d1 = delegate void() {...}
>     void delegate() d2 = stack_frame.delegate void() {...}
>   }
>In the code above, both delegate literals are non-copying delegates.

Interesting idea.  Never thought of nesting keyowrds in this manner.  I'm not sure if I like it though, I'll have to think about it for a bit.  Am I right in assuming that stack_frame is a keyword as well and not a type sitting off somewhere?


Sean


July 22, 2004
Sean Kelly wrote:
>>Ok, weird ponder here.  I've been playing with the idea that it would be nice to declare a delegate that has any arbitrary 'this' pointer, using the following syntax:
>>  MyClass foo = <whatever>;
>>  void delegate() del = foo.delegate void() { foo.x(); foo.y(); }
> 
> Interesting idea.  The only weird thing here is that this feature would enable a
> user to break encapsulation rules by accessing hidden members via these
> delegates.

You've confused me again here.  Assuming that the code in the delegate can't access anything that the function can access, how does this break encapsulation?

You can already sort of do this in D, although it requires you to create a wrapper class that has no purpose other than to give you a delegate. You can do this in D using the following code:

  MyClass foo = <whatever>;
  void hand_coded_delegate(void *arg) {
    MyClass foo = cast(MyClass)arg;
    foo.x(); foo.y();
  }
  union {
    void delegate() del;
    struct {
      void *arg;
      void function(void*) fptr;
    }
  } convert;
  convert.arg = cast(void*)foo;
  convert.fptr = &hand_coded_delegate;
  void delegate() del = convert.del;

So you see, the delegate can't do anything that the enclosing block can't do.

>>Then, you realize that the current stack delegate syntax can be viewed as syntax sugar:
>>  void bar() {
>>    void delegate() d1 = delegate void() {...}
>>    void delegate() d2 = stack_frame.delegate void() {...}
>>  }
>>In the code above, both delegate literals are non-copying delegates.
> 
> Interesting idea.  Never thought of nesting keyowrds in this manner.  I'm not
> sure if I like it though, I'll have to think about it for a bit.  Am I right in
> assuming that stack_frame is a keyword as well and not a type sitting off
> somewhere?

Yes.  My assumption is that stack_frame is a new keyword, which is a pointer to an anonymous structure type which models the local function variables.  It's sort of like 'this' for a stack frame.

July 22, 2004
I have a few friendly questions.  :)

I've followed the conversation so far, but one thing still escapes me: what would such a closure accomplish that a class with opCall cannot?  Is this trying to achieve some kind of efficency gain or just a better syntax (or both)?

In article <cdp5cu$11ui$1@digitaldaemon.com>, Sean Kelly says...
>>Then, you realize that the current stack delegate syntax can be viewed as syntax sugar:
>>   void bar() {
>>     void delegate() d1 = delegate void() {...}
>>     void delegate() d2 = stack_frame.delegate void() {...}
>>   }
>>In the code above, both delegate literals are non-copying delegates.
>
>Interesting idea.  Never thought of nesting keyowrds in this manner.  I'm not sure if I like it though, I'll have to think about it for a bit.  Am I right in assuming that stack_frame is a keyword as well and not a type sitting off somewhere?

Personally, I like how succinct this concept is.  I have the same question: is 'stack_frame' a new keyword or some type?  If it is keyword, wouldn't overloading 'new' be a little more appropriate, since it's getting stack frame all to itself?

>   void bar() {
>     void delegate() d1 = delegate void() {...}
>     void delegate() d2 = new delegate void() {...}
>   }


July 22, 2004
pragma  wrote:
> I have a few friendly questions.  :)
> 
> I've followed the conversation so far, but one thing still escapes me: what
> would such a closure accomplish that a class with opCall cannot?  Is this trying
> to achieve some kind of efficency gain or just a better syntax (or both)?

It's both.  If you implement this sort of functionality with a class with opCall, you have an unnecessary level of indirection; the 'this' argument to the delegate will be a pointer to your wrapper class, and you have to then read a member variable of the class to get the pointer to 'foo'.  Worse, you have to allocate, construct, and then later garbage collect a new class object on the heap.

In my reply to Sean, I wrote some D code that avoids all of these inefficiencies.  However, it's many lines of code.  So I'm suggesting that it would be good to use my syntax as it is far cleaner, easier-to-read code.

> In article <cdp5cu$11ui$1@digitaldaemon.com>, Sean Kelly says...
> 
>>>Then, you realize that the current stack delegate syntax can be viewed as syntax sugar:
>>>  void bar() {
>>>    void delegate() d1 = delegate void() {...}
>>>    void delegate() d2 = stack_frame.delegate void() {...}
>>>  }
>>>In the code above, both delegate literals are non-copying delegates.
>>
>>Interesting idea.  Never thought of nesting keyowrds in this manner.  I'm not
>>sure if I like it though, I'll have to think about it for a bit.  Am I right in
>>assuming that stack_frame is a keyword as well and not a type sitting off
>>somewhere?
> 
> Personally, I like how succinct this concept is.  I have the same question: is
> 'stack_frame' a new keyword or some type?  If it is keyword, wouldn't
> overloading 'new' be a little more appropriate, since it's getting stack frame
> all to itself?
> 
>>  void bar() {
>>    void delegate() d1 = delegate void() {...}
>>    void delegate() d2 = new delegate void() {...}
>>  }

This might make a lot of sense.  To its favor, it makes more explicit that new memory is being allocated (although using .dup is pretty explicit, as well).  One strike against it, however, is that it doesn't make immediately clear that something is being copied.  New typically allocates uninitialized data.

July 22, 2004
In article <cdp6ms$12g3$1@digitaldaemon.com>, Russ Lewis says...
>
>Sean Kelly wrote:
>>>Ok, weird ponder here.  I've been playing with the idea that it would be nice to declare a delegate that has any arbitrary 'this' pointer, using the following syntax:
>>>  MyClass foo = <whatever>;
>>>  void delegate() del = foo.delegate void() { foo.x(); foo.y(); }
>> 
>> Interesting idea.  The only weird thing here is that this feature would enable a user to break encapsulation rules by accessing hidden members via these delegates.
>
>You've confused me again here.  Assuming that the code in the delegate can't access anything that the function can access, how does this break encapsulation?

Oh I misunderstood.  When you said "hidden this pointer" I assumed you meant that the delegate would behave as if it were a first class member of foo. Interesting idea.


Sean


July 22, 2004
In article <cdp6ub$12kh$1@digitaldaemon.com>, pragma <EricAnderton at yahoo dot com> says...
>
>I have a few friendly questions.  :)
>
>I've followed the conversation so far, but one thing still escapes me: what would such a closure accomplish that a class with opCall cannot?  Is this trying to achieve some kind of efficency gain or just a better syntax (or both)?

Nothing really, but for some additional simplicity.  A returned class needs its own external declaration while delegates can be declared as a part of the function prototype.  Also, returning a class would require the programmer to manually copy the data he cares about while this dynamic closure idea would make the process automatic.


Seam


July 22, 2004
If delegates are allowed to point at the stack they were instatiated within then
the compiler has to be
smart enough to leave the stack around for the garbage collector to clean up
when the delegate is
finally done away with.   This seems strange...

Otherwise you'll end up with stackless delegates..

In article <cdoc6l$mkg$1@digitaldaemon.com>, David Medlock says...
>
>Russ Lewis wrote:
>
>> I am a big proponent of having some functionality that enables us to
>> copy stack delegates.  We don't want copying to be the default, however.
>>  Consider this code:
>> 
>> 
>> int foo() {
>>   int counter = 0;
>> 
>>   bar(void delegate(int val) { counter += arg; });
>> 
>>   return counter;
>> }
>> void bar(void delegate() dg) {
>>   foreach(whatever)
>>     dg(something);
>> }
>> 
>> 
>> You see, in this code, you want to give the delegate the capability to modify the real values on the stack.  You don't want it to be using a duplicate.
>> 
>> So what I've advocated is that we have the option to copy or not.
>> 
>> Sean Kelly wrote:
>
>I assume you meant to write 'counter += val'.
>
>Actually that seems an error in my definition of a closure. In the above situation the behavior I would expect from the compiler is all accessible variables not passed as params are *in*, so counter would have to be redeclared within the inner function.
>
>Pseudo example of what I am thinking of(internals):
>struct delegate { int size; void * data; void *funct; }
>
>Assigning a function to a delegate would mean ensuring the size/data parameters are valid.
>
>The only problem that remains would be giving a delegate function access to the *data* within the struct.
>
>The compiler could:
>Have code inserted before and after a delegate is called to handle
>copying the data to and from the stack(as mentioned).  Performance is
>extremely minimal because in most cases its just a few Push/Pops.
>
>-or-
>
>For each non-static function, have another version internally(AST) which is used when an assignment to a delegate happens.  The delegate version accesses local variables in its storage space instead of the stack(using the data*). Having a different version probably wouldnt be that bad, templates do this already.
>
>I realize this would be a PITA, but this would allow many functional idioms to be used.
>
>Sorry for the rambling, I hope this makes some sense.
>


July 22, 2004
Stack delegates work just like any code that passes pointers to stack variables: they are valid only as long as the function doesn't return, or leave the block of code where the variable resides.  So this code is perfectly ok in C/C++ and D:
  void foo() {
    int var = 0;
    bar(&var);
  }
so long as bar() doesn't save the pointer.  bar() should never use the pointer after it returns to foo().

Likewise, a stack delegate is valid only as long as the stack frame is valid.  So you're right, you can end up with stackless delegates...but this is just the way they work.  The programmer has to be aware of it.

Of course, this whole discussion is about the fact that this would not be an issue if it were possible to have stack delegates which use copies of the stack.

Sha Chancellor wrote:
> If delegates are allowed to point at the stack they were instatiated within then
> the compiler has to be smart enough to leave the stack around for the garbage collector to clean up
> when the delegate is finally done away with.   This seems strange...
> 
> Otherwise you'll end up with stackless delegates..