July 23, 2004
In article <cdpbel$14k4$1@digitaldaemon.com>, Russ Lewis says...
>
>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.

Here's a few thoughts: what happens when a delegate, executing on it's own stack-frame (copied into GC'd memory for argument's sake) calls another function?  Would the called function's stack frame be allocated back on the thread's stack (provided it's not another stack delegate)?  How would recursion within a stack-delegate be handled? ...on the thread's stack in all cases, perhaps?

The reason why I bring this up is that you may be able to create a full-on reference implementation in D itself (with some liberal application of assembler of course).  All you'd need to to is push the stack-segment and stack-pointer onto the current stack for safe-keeping before setting it to what stack you're going to use (this means that whatever stack space the delegate needs would have to be at least 16 bytes to accomodate this).  This would apply to entering the stack-delegate as well as calling functions that lead out of it.

- Pragma



July 23, 2004
pragma  wrote:
> Here's a few thoughts: what happens when a delegate, executing on it's own
> stack-frame (copied into GC'd memory for argument's sake) calls another
> function?  Would the called function's stack frame be allocated back on the
> thread's stack (provided it's not another stack delegate)?  How would recursion
> within a stack-delegate be handled? ...on the thread's stack in all cases,
> perhaps?
> 
> The reason why I bring this up is that you may be able to create a full-on
> reference implementation in D itself (with some liberal application of assembler
> of course).  All you'd need to to is push the stack-segment and stack-pointer
> onto the current stack for safe-keeping before setting it to what stack you're
> going to use (this means that whatever stack space the delegate needs would have
> to be at least 16 bytes to accomodate this).  This would apply to entering the
> stack-delegate as well as calling functions that lead out of it.

I think that perhaps I miscommunicated here.  I don't think that the stack frame of a delegate should ever reside on the heap.  Instead, I think that some of the local variables of a certain delegate should reside inside a struct which resides on the heap.  The difference may be small for the programmer, but the difference is massive for implementation.  I'm going to try to illustrate.  Please forgive the amount of hex is will require...

  int delegate() foo() {
    int counter;
    return stack_frame.dup.delegate int(int val)
      { counter += val; return val; }
  }

  void bar() {
    int delegate() del = foo();
    foreach(int i; <whatever>)
      printf("Value = %d, retval = %d\n", i,del(i));
  }

Ok, so the code here has a stack delegate which gets duplicated.  What happens when bar() calls that delegate?  This is how I imagine the stack would look:

  ADDRESS 0xB080 (STACK)
    Local variable 'del' (8 bytes)
      obj = 0x8000
      fptr = 0x4000
    Local variable 'i' (4 bytes)
  ADDRESS 0xB070 (STACK)
    Argument 'this' (4 bytes)
      ptr = 0x8000  /* note: this is the 'obj' from above */

  ADDRESS 0x8000 (HEAP)
    Variable 'counter'

The point I'm trying to communicate here is that the stack frame for the delegate resides on the same stack as everybody else.  That stack frame includes a pointer variable which points to a location in the heap where copied variables (things that USED TO BE on the stack) now reside.

A delegate can then call any other function it wants to.  It continues to use the stack just like any other function does.  No magic necessary.

You can see how you can implement this in one of my previous posts in this thread.  All you have to do is to create a struct type, and enclose all of the copied stack variables in a struct of that type.

July 23, 2004
Forgive me Russ for not quite following the reasoning behind this. Would you mind clarifying why this delegate example is so much more valuable that, say, foo() returning an Interface or even a base-class? I mean, wouldn't something like this provide the equivalent functionality?

IDelegate foo()
{
    class Foo : IDelegate
    {
       int counter;
       dg(int val) {counter += val; return counter;}
     }

    return new Foo;
}

etc. etc.

Certainly, there's a memory allocation there; but that cost can be avoided at runtime through various means. What's the important bit I'm missing? (yeah, yeah; apart from a brain ... :~)

- Kris


"Russ Lewis" <spamhole-2001-07-16@deming-os.org> wrote in message news:cdq7ii$1ho2$1@digitaldaemon.com...
> pragma  wrote:
> > Here's a few thoughts: what happens when a delegate, executing on it's
own
> > stack-frame (copied into GC'd memory for argument's sake) calls another function?  Would the called function's stack frame be allocated back on
the
> > thread's stack (provided it's not another stack delegate)?  How would
recursion
> > within a stack-delegate be handled? ...on the thread's stack in all
cases,
> > perhaps?
> >
> > The reason why I bring this up is that you may be able to create a
full-on
> > reference implementation in D itself (with some liberal application of
assembler
> > of course).  All you'd need to to is push the stack-segment and
stack-pointer
> > onto the current stack for safe-keeping before setting it to what stack
you're
> > going to use (this means that whatever stack space the delegate needs
would have
> > to be at least 16 bytes to accomodate this).  This would apply to
entering the
> > stack-delegate as well as calling functions that lead out of it.
>
> I think that perhaps I miscommunicated here.  I don't think that the stack frame of a delegate should ever reside on the heap.  Instead, I think that some of the local variables of a certain delegate should reside inside a struct which resides on the heap.  The difference may be small for the programmer, but the difference is massive for implementation.  I'm going to try to illustrate.  Please forgive the amount of hex is will require...
>
>    int delegate() foo() {
>      int counter;
>      return stack_frame.dup.delegate int(int val)
>        { counter += val; return val; }
>    }
>
>    void bar() {
>      int delegate() del = foo();
>      foreach(int i; <whatever>)
>        printf("Value = %d, retval = %d\n", i,del(i));
>    }
>
> Ok, so the code here has a stack delegate which gets duplicated.  What happens when bar() calls that delegate?  This is how I imagine the stack would look:
>
>    ADDRESS 0xB080 (STACK)
>      Local variable 'del' (8 bytes)
>        obj = 0x8000
>        fptr = 0x4000
>      Local variable 'i' (4 bytes)
>    ADDRESS 0xB070 (STACK)
>      Argument 'this' (4 bytes)
>        ptr = 0x8000  /* note: this is the 'obj' from above */
>
>    ADDRESS 0x8000 (HEAP)
>      Variable 'counter'
>
> The point I'm trying to communicate here is that the stack frame for the delegate resides on the same stack as everybody else.  That stack frame includes a pointer variable which points to a location in the heap where copied variables (things that USED TO BE on the stack) now reside.
>
> A delegate can then call any other function it wants to.  It continues to use the stack just like any other function does.  No magic necessary.
>
> You can see how you can implement this in one of my previous posts in this thread.  All you have to do is to create a struct type, and enclose all of the copied stack variables in a struct of that type.
>


July 23, 2004
"pragma" <EricAnderton at yahoo dot compragma_member@pathlink.com> wrote in message news:cdp6ub$12kh$1@digitaldaemon.com...
> 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)?

I tryed to folow you conversation. And now I have only one wish.

Pls, could someone of you add some of  this (or other) useful/essential
examples to the : dsource.org/tutorial / delegates section (or Wiki)? I
think many people will be grateful to you (especially me). Thanks.

-----
Yuriy.


July 23, 2004
Kris wrote:
> Forgive me Russ for not quite following the reasoning behind this. Would you
> mind clarifying why this delegate example is so much more valuable that,
> say, foo() returning an Interface or even a base-class? I mean, wouldn't
> something like this provide the equivalent functionality?
> 
> IDelegate foo()
> {
>     class Foo : IDelegate
>     {
>        int counter;
>        dg(int val) {counter += val; return counter;}
>      }
> 
>     return new Foo;
> }
> 
> etc. etc.
> 
> Certainly, there's a memory allocation there; but that cost can be avoided
> at runtime through various means. What's the important bit I'm missing?
> (yeah, yeah; apart from a brain ... :~)
> 
> - Kris
> 
> 
> "Russ Lewis" <spamhole-2001-07-16@deming-os.org> wrote in message
> news:cdq7ii$1ho2$1@digitaldaemon.com...
> 
>>pragma  wrote:
>>
>>>Here's a few thoughts: what happens when a delegate, executing on it's
> 
> own
> 
>>>stack-frame (copied into GC'd memory for argument's sake) calls another
>>>function?  Would the called function's stack frame be allocated back on
> 
> the
> 
>>>thread's stack (provided it's not another stack delegate)?  How would
> 
> recursion
> 
>>>within a stack-delegate be handled? ...on the thread's stack in all
> 
> cases,
> 
>>>perhaps?
>>>
>>>The reason why I bring this up is that you may be able to create a
> 
> full-on
> 
>>>reference implementation in D itself (with some liberal application of
> 
> assembler
> 
>>>of course).  All you'd need to to is push the stack-segment and
> 
> stack-pointer
> 
>>>onto the current stack for safe-keeping before setting it to what stack
> 
> you're
> 
>>>going to use (this means that whatever stack space the delegate needs
> 
> would have
> 
>>>to be at least 16 bytes to accomodate this).  This would apply to
> 
> entering the
> 
>>>stack-delegate as well as calling functions that lead out of it.
>>
>>I think that perhaps I miscommunicated here.  I don't think that the
>>stack frame of a delegate should ever reside on the heap.  Instead, I
>>think that some of the local variables of a certain delegate should
>>reside inside a struct which resides on the heap.  The difference may be
>>small for the programmer, but the difference is massive for
>>implementation.  I'm going to try to illustrate.  Please forgive the
>>amount of hex is will require...
>>
>>   int delegate() foo() {
>>     int counter;
>>     return stack_frame.dup.delegate int(int val)
>>       { counter += val; return val; }
>>   }
>>
>>   void bar() {
>>     int delegate() del = foo();
>>     foreach(int i; <whatever>)
>>       printf("Value = %d, retval = %d\n", i,del(i));
>>   }
>>
>>Ok, so the code here has a stack delegate which gets duplicated.  What
>>happens when bar() calls that delegate?  This is how I imagine the stack
>>would look:
>>
>>   ADDRESS 0xB080 (STACK)
>>     Local variable 'del' (8 bytes)
>>       obj = 0x8000
>>       fptr = 0x4000
>>     Local variable 'i' (4 bytes)
>>   ADDRESS 0xB070 (STACK)
>>     Argument 'this' (4 bytes)
>>       ptr = 0x8000  /* note: this is the 'obj' from above */
>>
>>   ADDRESS 0x8000 (HEAP)
>>     Variable 'counter'
>>
>>The point I'm trying to communicate here is that the stack frame for the
>>delegate resides on the same stack as everybody else.  That stack frame
>>includes a pointer variable which points to a location in the heap where
>>copied variables (things that USED TO BE on the stack) now reside.
>>
>>A delegate can then call any other function it wants to.  It continues
>>to use the stack just like any other function does.  No magic necessary.
>>
>>You can see how you can implement this in one of my previous posts in
>>this thread.  All you have to do is to create a struct type, and enclose
>>all of the copied stack variables in a struct of that type.
>>
> 
This is what I meant above:

"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."

The delegate version would not change local variables on the stack, but as dereferenced through a pointer on the stack.

Doing this requires that an assignment of a function to a delegate ensures memory is set aside, whereas assigning a delegate to another just copies the data(struct mentioned above) from the delegate.

July 23, 2004
Kris wrote:
> Forgive me Russ for not quite following the reasoning behind this. Would you
> mind clarifying why this delegate example is so much more valuable that,
> say, foo() returning an Interface or even a base-class? I mean, wouldn't
> something like this provide the equivalent functionality?
> 
> IDelegate foo()
> {
>     class Foo : IDelegate
>     {
>        int counter;
>        dg(int val) {counter += val; return counter;}
>      }
> 
>     return new Foo;
> }

A class provides equivalent functionality, but, as you noted, it requires much more overhead.  Plus, I would like to declare the whole duplicated stack delegate on a single line, rather than having the complexity and readability issues of having to declare a whole class or struct just for this purpose.

Incidentally, when you are only using a single interface function (and you don't need to do anything to the object itself), delegates are always more flexible than interfaces.  They can interact with other classes, which don't share any common base class or interface, and don't require the declaration of some additional Interface.  So I'd prefer this code, if I was going to use a class:

int delegate() foo() {
  class Foo {
    int counter;
    this() { counter = 0; }
    int dg(int val) { counter += val; return counter; }
  }

  Foo ret = new Foo;
  return &ret.dg;
}

July 23, 2004
Thanks!

Sure, delegates are great for certain tasks. I guess my fear is trying to make them do things that might perhaps be better off approached from the other direction (a syntax and methodology for non-verbose & low-cost class instantiation). The latter would expose the same benefits you propose, yet support more than one callback and provide arguably better encapsulation.

Just an observation though. What you propose is certainly interesting.

- Kris

"Russ Lewis" <spamhole-2001-07-16@deming-os.org> wrote in message news:cdr9gr$23j0$1@digitaldaemon.com...
> Kris wrote:
> > Forgive me Russ for not quite following the reasoning behind this. Would
you
> > mind clarifying why this delegate example is so much more valuable that, say, foo() returning an Interface or even a base-class? I mean, wouldn't something like this provide the equivalent functionality?
> >
> > IDelegate foo()
> > {
> >     class Foo : IDelegate
> >     {
> >        int counter;
> >        dg(int val) {counter += val; return counter;}
> >      }
> >
> >     return new Foo;
> > }
>
> A class provides equivalent functionality, but, as you noted, it requires much more overhead.  Plus, I would like to declare the whole duplicated stack delegate on a single line, rather than having the complexity and readability issues of having to declare a whole class or struct just for this purpose.
>
> Incidentally, when you are only using a single interface function (and you don't need to do anything to the object itself), delegates are always more flexible than interfaces.  They can interact with other classes, which don't share any common base class or interface, and don't require the declaration of some additional Interface.  So I'd prefer this code, if I was going to use a class:
>
> int delegate() foo() {
>    class Foo {
>      int counter;
>      this() { counter = 0; }
>      int dg(int val) { counter += val; return counter; }
>    }
>
>    Foo ret = new Foo;
>    return &ret.dg;
> }
>


July 23, 2004
Kris wrote:
> Thanks!
> 
> Sure, delegates are great for certain tasks. I guess my fear is trying to
> make them do things that might perhaps be better off approached from the
> other direction (a syntax and methodology for non-verbose & low-cost class
> instantiation). The latter would expose the same benefits you propose, yet
> support more than one callback and provide arguably better encapsulation.
> 
> Just an observation though. What you propose is certainly interesting.

I agree that it would be nice to have some mechanism for very low-cost classes.  Whether that is a "better" approach or not...well, we'll probably not know until they are available! :)

It has occurred to me before that, if a single-function interface is just a delegate, then isn't a multifunction interface just a struct of delegates, sort of?

This interface:
  interface FooI {
    int foo();
    void bar(int);
    char baz(char[]);
  }

is a lot like this struct:
  struct FooS {
    int delegate() foo;
    void delegate(int) bar;
    char delegate(char[]) baz;

    void delegate() do_delete;
      /* deletes the object */
    Object delegate() getObj;
      /* gets the obj pointer, so you can cast it */
  }

so you could do this:
  class MyClass {
    int asdf() {...}
    void jkl(int) {...}
    char qwerty(char[]) {...}

    ~this() {...}

    // this function would be unnecessary if
    // stack duplicate delegates were implemented
    Object getMe() { return this; }
  }

  FooS *GetFooS(MyClass obj) {
    FooS *ret = new FooS[1];
    ret.foo = &obj.asdf;
    ret.bar = &obj.jkl;
    ret.baz = &obj.qwerty;
    ret.do_delete = &.obj~this;
    ret.getObj = &obj.getMe;
    return ret;
  }

So a struct of delegates is more adaptible than an interface...the names in the class don't have to match the names in the interface.  Of course, this sort of thing has a couple of big disadvantages:
  * Size.  Since each ptr is a delegate, it takes 8 bytes.  Plus, each object has to have its own struct...no shared vtbl
  * Hard to declare

However, if we all agreed that this sort of thing was useful, then it might be possible to devise (for 2.0) some new, better solution for this.

July 26, 2004
I posted an example, but need to edit it.  How do I do that?

Blandger wrote:
> "pragma" <EricAnderton at yahoo dot compragma_member@pathlink.com> wrote in
> message news:cdp6ub$12kh$1@digitaldaemon.com...
> 
>>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)?
> 
> 
> I tryed to folow you conversation. And now I have only one wish.
> 
> Pls, could someone of you add some of  this (or other) useful/essential
> examples to the : dsource.org/tutorial / delegates section (or Wiki)? I
> think many people will be grateful to you (especially me). Thanks.
> 
> -----
> Yuriy.
> 
> 

July 27, 2004
"Russ Lewis" <spamhole-2001-07-16@deming-os.org> wrote in message news:ce3u1v$1h7j$1@digitaldaemon.com...

> I posted an example, but need to edit it.  How do I do that?

Sorry I didn't understand a question.

I'd like to see good delegete examples in the dsource.org -> tutorial section. To post it you can apply to Brad. He is admin there 'brad at dsource dot org'

You can post them in the appropriate D Wiki page. Though I don't have a experience using it :(

----
Yuriy.