www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Delegates

reply Robin Allen <r.a3 ntlworld.com> writes:
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!
Jan 19 2007
next sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
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 :).
Jan 19 2007
parent reply Robin Allen <r.a3 ntlworld.com> writes:
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).
Jan 24 2007
parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
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.
Jan 24 2007
prev sibling next sibling parent reply Pragma <ericanderton yahoo.removeme.com> writes:
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
Jan 19 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Pragma wrote:
 Like Fritz said,
*ahem*. That's an _s_, not a _z_. I'm Dutch, not German :).
Jan 19 2007
parent Pragma <ericanderton yahoo.removeme.com> writes:
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
Jan 19 2007
prev sibling parent Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
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
Jan 20 2007