Thread overview
Local variable inside delegate literal
Dec 23, 2009
Daniel
Dec 23, 2009
bearophile
Dec 23, 2009
Daniel
Dec 23, 2009
downs
Dec 23, 2009
Sergey Gromov
December 23, 2009
I'm writing some gui code, and am currently trying to make something equivalent to this:

int delegate()[] funcs;
funcs.length = 3;

foreach(i, ref f; funcs)
{
  f = int() { return i; }
}

foreach(f; funcs)
{
  writeln(f());
}

Prints:
3
3
3

I want it to print
0
1
2

Is there anyway to get this behaviour using delegate literals initialized with a runtime loop?
December 23, 2009
Daniel:

> I'm writing some gui code, and am currently trying to make something equivalent to this:
> 
> int delegate()[] funcs;
> funcs.length = 3;
> 
> foreach(i, ref f; funcs)
> {
>   f = int() { return i; }
> }
> 
> foreach(f; funcs)
> {
>   writeln(f());
> }

This is D2 code that actually compiles:

import std.stdio: writeln;

void main() {
    auto funcs = new int delegate()[3];

    foreach (i, ref f; funcs)
        f = { return cast(int)i; };

    foreach (f; funcs)
        writeln(f());
}


This is a good version in D2:

import std.stdio: writeln;

class Foo {
    int i;
    this(int i) { this.i = i; }
    int opCall() { return this.i; }
}

void main() {
    auto funcs = new Foo[3];

    foreach (i, ref f; funcs)
        f = new Foo(i);

    foreach (f; funcs)
        writeln(f());
}


Or even cheaper:

import std.stdio: writeln;

struct Foo {
    int i;
    this(int i) { this.i = i; }
    int opCall() { return this.i; }
}

void main() {
    auto funcs = new Foo[3];

    foreach (i, ref f; funcs)
        f = Foo(i);

    foreach (f; funcs)
        writeln(f());
}

Often the better code is not the most compact one, but the most explicit one.

Bye,
bearophile
December 23, 2009
bearophile Wrote:

> Daniel:
> 
> > I'm writing some gui code, and am currently trying to make something equivalent to this:
> > 
> > int delegate()[] funcs;
> > funcs.length = 3;
> > 
> > foreach(i, ref f; funcs)
> > {
> >   f = int() { return i; }
> > }
> > 
> > foreach(f; funcs)
> > {
> >   writeln(f());
> > }
> 
> This is D2 code that actually compiles:
> 
> import std.stdio: writeln;
> 
> void main() {
>     auto funcs = new int delegate()[3];
> 
>     foreach (i, ref f; funcs)
>         f = { return cast(int)i; };
> 
>     foreach (f; funcs)
>         writeln(f());
> }
> 
> 
> This is a good version in D2:
> 
> import std.stdio: writeln;
> 
> class Foo {
>     int i;
>     this(int i) { this.i = i; }
>     int opCall() { return this.i; }
> }
> 
> void main() {
>     auto funcs = new Foo[3];
> 
>     foreach (i, ref f; funcs)
>         f = new Foo(i);
> 
>     foreach (f; funcs)
>         writeln(f());
> }
> 
> 
> Or even cheaper:
> 
> import std.stdio: writeln;
> 
> struct Foo {
>     int i;
>     this(int i) { this.i = i; }
>     int opCall() { return this.i; }
> }
> 
> void main() {
>     auto funcs = new Foo[3];
> 
>     foreach (i, ref f; funcs)
>         f = Foo(i);
> 
>     foreach (f; funcs)
>         writeln(f());
> }
> 
> Often the better code is not the most compact one, but the most explicit one.
> 
> Bye,
> bearophile

I actually needed it to be a delegate to interact with the rest of my code, but I used the idea of making a copy of the index variable each loop iteration, using a generating function returning a closure.

Thanks for your help.



import std.stdio: writeln;

void main() {
    auto funcs = new int delegate()[3];

    int delegate() makedg(int i)
    {
        return { return i; };
    }

    foreach (i, ref f; funcs)
        f = makedg(i);

    foreach (f; funcs)
        writeln(f());
}

Or

void main() {
    auto funcs = new int delegate()[3];

    foreach (i, ref f; funcs)
        f = (int i) { return { return i; }; }(i);

    foreach (f; funcs)
        writeln(f());
}
December 23, 2009
Daniel wrote:
> I'm writing some gui code, and am currently trying to make something equivalent to this:
> 
> int delegate()[] funcs;
> funcs.length = 3;
> 
> foreach(i, ref f; funcs)
> {
>   f = int() { return i; }
> }
> 
> foreach(f; funcs)
> {
>   writeln(f());
> }
> 
> Prints:
> 3
> 3
> 3
> 
> I want it to print
> 0
> 1
> 2
> 
> Is there anyway to get this behaviour using delegate literals initialized with a runtime loop?

This is how you do it in 1.0:

import std.stdio, std.bind;

void main() {
  auto funcs = new int delegate()[3];


  foreach (i, ref f; funcs)
    f = bind((int i) { return i; }, i).ptr();

  foreach (f; funcs)
    writefln(f());
}

--outputs--

0
1
2
December 23, 2009
Daniel wrote:
> int delegate()[] funcs;
> funcs.length = 3;
> 
> foreach(i, ref f; funcs)
> {
>   f = int() { return i; }
> }
> 
> foreach(f; funcs)
> {
>   writeln(f());
> }

First, there are syntax errors in your example.  It should be

    f = delegate int() { return i; };

Second, this works in D2:

    foreach(i, ref f; funcs)
    {
      void blah() {
        auto j = i;
        f = delegate int() { return j; };
      }
      blah();
    }

But this doesn't, outputs 2, 2, 2:

    foreach(i, ref f; funcs)
    {
      auto j = i;
      f = delegate int() { return j; };
    }

And this crashes:

    foreach(i, ref f; funcs)
    {
      ({
        auto j = i;
        f = delegate int() { return j; };
      })();
    }

I think these 3 variants should be equivalent.