confusing (buggy?) closure behaviour

Zoran Isailovski dmd.zoc at spamgourmet.com
Fri Dec 12 11:28:01 PST 2008


Denis Koroskin Wrote:

> On Fri, 12 Dec 2008 19:32:03 +0300, Zoran Isailovski  
> <dmd.zoc at spamgourmet.com> wrote:
> 
> > I'm an experienced C#, Java and Python programmer, and have employed  
> > closures (and C# delegates) upon numerous occasions. While experimenting  
> > with D closures and delegates, I was stroke by a phenomenon I cannot  
> > explain. Here's the code:
> >
> > module closures01;
> >
> > import std.stdio;
> >
> > alias int delegate(int arg) Handler;
> >
> > Handler incBy(int n)
> > {
> > 	return delegate(int arg){ return arg + n; };
> > }
> >
> > Handler mulBy(int n)
> > {
> > 	return delegate(int arg){ return arg * n; };
> > }
> >
> > void test1()
> > {
> > 	writefln("\ntest1:\n----------------------------------------");
> > 	int x = 10, y;
> > 	y = mulBy(3)(x); writefln("%d * 3 -> %d", x, y);
> > 	y = mulBy(4)(x); writefln("%d * 4 -> %d", x, y);
> > 	y = incBy(2)(x); writefln("%d + 2 -> %d", x, y);
> > }
> >
> > void test2()
> > {
> > 	writefln("\ntest2:\n----------------------------------------");
> > 	int x = 10, y;
> > 	Handler times3 = mulBy(3);
> > 	Handler times4 = mulBy(4);
> > 	Handler plus2 = incBy(2);
> > 	y = times3(x); writefln("%d * 3 -> %d", x, y);
> > 	y = times4(x); writefln("%d * 4 -> %d", x, y);
> > 	y = plus2(x); writefln("%d + 2 -> %d", x, y);
> > }
> >
> > public void run()
> > {
> > 	test1();
> > 	test2();
> > }
> >
> > /* **************************************** *
> >  * Compiled with: Digital Mars D Compiler v1.030
> >  *
> >  * (Unexplainable) program output:
> > test1:
> > ----------------------------------------
> > 10 * 3 -> 30
> > 10 * 4 -> 40
> > 10 + 2 -> 12
> >
> > test2:
> > ----------------------------------------
> > 10 * 3 -> 20
> > 10 * 4 -> 42846880
> > 10 + 2 -> 4284698
> >
> > * **************************************** */
> >
> > What goes wrong???
> 
> I'd say that it works as expected and here is why.
> 
> First of all, there are two types of closures:  static and dynamic  
> closures.
> Closures work by having a hidden pointer to function frame where all local  
> variables are stored.
> 
> When a static closure is created, all the function local variables are  
> stored on stack.
> It has an advantage that no memory allocation takes place (fast).
> It has a disadvantage that once the delegate leaves the scope, it becomes  
> invalid since variables were stored on stack and the stack is probably  
> overwritten (unsafe).
> 
> Dynamic closure allocates memory in a heap and all the local variables are  
> placed there.
> It has a disadvantage that memory is allocated for dynamic closure (might  
> be slow if dynamic closure are created often).
> It has an advantage that dynamic closure may leave the scope, i.e. you may  
> save it and call whenever you want.
> 
> D1 support static closures only! That's why your code doesn't work (in  
> test1 stack is still valid, but in test2 stack gets overwritten)
> D2 has support for dynamic closures. Just try it - your sample works as is.

An addition:

Given the complexness of the criteria when a closure works and when not, I would vote for a compiler error on inappropriate closures usage. (In Java, closures cannot handle mutable values on the stack, so it's an error for a method to return a closure that refers to a non-final argument.)


More information about the Digitalmars-d-learn mailing list