Thread overview
Delegates
Jan 19, 2007
Robin Allen
Jan 19, 2007
Frits van Bommel
Jan 24, 2007
Robin Allen
Jan 24, 2007
Frits van Bommel
Jan 19, 2007
Pragma
Jan 19, 2007
Frits van Bommel
Jan 19, 2007
Pragma
Jan 20, 2007
Bruno Medeiros
January 19, 2007
I'm trying to figure out delegates. From what I can see, they're intended to be what other languages call closures?

So, say I wanted to write some functions for signal processing. I'd define a Wave type as a function of time, like this:

alias float delegate(float) Wave;

and a function to return a sine wave of a specified frequency like this:

Wave sine(float freq)
{
  return delegate(float t) { return std.math.sin(2*std.math.PI*t); };
}

When I realised this didn't work at all, I cut back the code to something very basic and realised that even this doesn't work:

Wave constant(float value)
{
  return delegate(float t) { return value; }
}

Wave w0 = constant(6);
float x = w0(42); // x is now 42, not 6

But it does work if I change the function to:

Wave constant(float value)
{
  float _value = value;
  return delegate(float t) { return _value;}
}

I hesitate to cry "bug" because there's quite a large possibility that I don't understand delegates at all, but it seems a little weird.

Another oddity I found, and which I hope someone could explain, is:

Wave ramp(float start, float end, float length)
{
	float _start = start;
	float _end = end;
	float _length = length;

	return delegate(float t)
	{
		writefln("%f %f",t,_length);
		float fact = math.remainder(t, _length);
		return _start + (_end-_start)*fact;
	};
}

The above function's behaviour changes if I just commment out the writefln line. That can't be right!
January 19, 2007
Robin Allen wrote:
> I'm trying to figure out delegates. From what I can see, they're intended to be what other languages call closures?
> 
> So, say I wanted to write some functions for signal processing. I'd define a Wave type as a function of time, like this:
> 
> alias float delegate(float) Wave;
> 
> and a function to return a sine wave of a specified frequency like this:
> 
> Wave sine(float freq)
> {
>   return delegate(float t) { return std.math.sin(2*std.math.PI*t); };
> }
[Snipped some similar examples]

Returning delegate literals is never a good idea.
A recent thread "Trouble with anon delegates." should explain the issue. I suggest you read it :).
January 19, 2007
Robin Allen wrote:
> I'm trying to figure out delegates. From what I can see, they're intended to be what other languages call closures?
> 
> So, say I wanted to write some functions for signal processing. I'd define a Wave type as a function of time, like this:
> 
> alias float delegate(float) Wave;
> 
> and a function to return a sine wave of a specified frequency like this:
> 
> Wave sine(float freq)
> {
>   return delegate(float t) { return std.math.sin(2*std.math.PI*t); };
> }
> 
> When I realised this didn't work at all, I cut back the code to something very basic and realised that even this doesn't work:
> 
> Wave constant(float value)
> {
>   return delegate(float t) { return value; }
> }
> 
> Wave w0 = constant(6);
> float x = w0(42); // x is now 42, not 6
> 
> But it does work if I change the function to:
> 
> Wave constant(float value)
> {
>   float _value = value;
>   return delegate(float t) { return _value;}
> }
> 
> I hesitate to cry "bug" because there's quite a large possibility that I don't understand delegates at all, but it seems a little weird.
> 
> Another oddity I found, and which I hope someone could explain, is:
> 
> Wave ramp(float start, float end, float length)
> {
> 	float _start = start;
> 	float _end = end;
> 	float _length = length;
> 	
> 	return delegate(float t)
> 	{
> 		writefln("%f %f",t,_length);
> 		float fact = math.remainder(t, _length);
> 		return _start + (_end-_start)*fact;
> 	};
> }
> 
> The above function's behaviour changes if I just commment out the writefln line. That can't be right!

Like Fritz said, returning an anonymous delegate is never a good idea.  The 'delegate' created is really a function bound to the current chunk of the call stack at the point of creation - so once you return it, it's invalid.

-- 
- EricAnderton at yahoo
January 19, 2007
Pragma wrote:
> Like Fritz said,

*ahem*. That's an _s_, not a _z_.

I'm Dutch, not German :).
January 19, 2007
Frits van Bommel wrote:
> Pragma wrote:
>> Like Fritz said,
> 
> *ahem*. That's an _s_, not a _z_.
> 
> I'm Dutch, not German :).

My sincerest apologies.  Darn phonetics getting in the way again. :)

(Feel free to spell my first name with a 'k' in the future)

-- 
- EricAnderton at yahoo
January 20, 2007
Robin Allen wrote:
> I'm trying to figure out delegates. From what I can see, they're intended to be what other languages call closures?
> 

Not exactly. Delegates and delegate literals (aka anonymous delegates) are what other languages, namely functional ones, call lambda expressions.
Closures are an optional language feature of lambda-expressions/delegate-literals, that allows such literal to reference variable outside its scope. D implements closures but with some quirks: if the variables referenced externally are stack allocated, then when their stack frame life ends, it is invalid to reference such variables, and consequently use the delegate. (and this happens often)
This problem is never present with LISP for example, because all data is heap-allocated.

-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
January 24, 2007
Frits van Bommel Wrote:

> Robin Allen wrote:
> > I'm trying to figure out delegates. From what I can see, they're intended to be what other languages call closures?
> > 
> > So, say I wanted to write some functions for signal processing. I'd define a Wave type as a function of time, like this:
> > 
> > alias float delegate(float) Wave;
> > 
> > and a function to return a sine wave of a specified frequency like this:
> > 
> > Wave sine(float freq)
> > {
> >   return delegate(float t) { return std.math.sin(2*std.math.PI*t); };
> > }
> [Snipped some similar examples]
> 
> Returning delegate literals is never a good idea.
> A recent thread "Trouble with anon delegates." should explain the issue.
> I suggest you read it :).

Thanks, that cleared things up a bit. From what was said in that thread, it looks like what I'm trying to do isn't possible. Making it so that you *can* return delegate literals would be a good move IMO, but I've no idea how plausible that is (though I do know Lua and ECMAscript let you do it).
January 24, 2007
Robin Allen wrote:
> Frits van Bommel Wrote:
> 
>> Robin Allen wrote:
>>> I'm trying to figure out delegates. From what I can see, they're intended to be what other languages call closures?
>>>
>>> So, say I wanted to write some functions for signal processing. I'd define a Wave type as a function of time, like this:
>>>
>>> alias float delegate(float) Wave;
>>>
>>> and a function to return a sine wave of a specified frequency like this:
>>>
>>> Wave sine(float freq)
>>> {
>>>   return delegate(float t) { return std.math.sin(2*std.math.PI*t); };
>>> }
>> [Snipped some similar examples]
>>
>> Returning delegate literals is never a good idea.
>> A recent thread "Trouble with anon delegates." should explain the issue. I suggest you read it :).
> 
> Thanks, that cleared things up a bit. From what was said in that thread, it looks like what I'm trying to do isn't possible. Making it so that you *can* return delegate literals would be a good move IMO, but I've no idea how plausible that is (though I do know Lua and ECMAscript let you do it).

Yes, scripting languages often allow it, as do functional languages.

It's something that comes up rather often though, and someday Walter may be persuaded to implement it. It may be a bit tricky to do (efficiently), though.

There's a workaround, by the way:
-----
// Warning: untested code, but something like this should work.
float delegate(float) foo(float freq)
{
    struct Data
    {
        float freq;
        float foo(float t) { return freq * t; } // or whatever
    }
    Data* d = new Data;
    d.freq = freq;
    return &d.foo;
}
-----

It's certainly not as pretty, but it gets the job done.