tags:

views:

172

answers:

1

Here is a simple generator in C#.

    IEnumerable<int> Foo()
    {
        int a = 1, b = 1;
        while(true)
        {
            yield return b;
            int temp = a + b;
            a = b;
            b = temp;
        }
    }

How do I write a similar generator in Digital Mars D?

(The question is about the yield return statement)

Thanks!


Update. That's interesting. Since I'm just generating a mathematical sequence, using recurrence may be a good option.

auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);

foreach (e; take(fib, 10)) // <- prints first ten numbers from the sequence
{ 
    writeln(e); 
}
+4  A: 

There's no exact equivalent in D. Here are some rough equivalents:

Using opApply-style internal iteration. This doesn't allow iterating over two iterators in lockstep, though:

struct Foo {
    int opApply(int delegate(ref int) dg) {
        int a = 1, b = 1;
        int result;
        while(true) {
            result = dg(b);
            if(result) break;
            int temp = a + b;
            a = b;
            b = temp;
        }

        return result;
    }
}

void main() {
    // Show usage:
    Foo foo;
    foreach(elem; foo) {
        // Do stuff.
    }
}

Use ranges. These are slightly harder to write in some cases, but are very efficient and allow lockstep iteration. This can also be iterated over with a foreach loop, exactly like the opApply version:

struct Foo {
    int a = 1, b = 1;

    int front() @property {
        return b;
    }

    void popFront() {
        int temp = a + b;
        a = b;
        b = temp;
    }

    // This range is infinite, i.e. never empty.
    enum bool empty = false;

    typeof(this) save() @property { return this; }
}

If you really need coroutine-style stuff you can combine ranges and opApply together using core.thread.Fiber, but you'll probably find that either ranges or opApply does what you need almost all the time.

dsimcha
While the D version is a little more verbose, it is at least more readable: I just can't get myself over that Foo should return 1 every time (b is assigned 1 in the very beginning). Also every language does things a little differently, for example Ruby is basically the opApply version without the struct overhead.
he_the_great
@he_the_great: The other tradeoff is that both D versions are much more efficient. While coroutine/generator style iteration can be simulated using fibers, I think pretty syntax for it was intentionally omitted because it costs about a hundred cycle context switch on each iteration. The opApply version costs maybe 5 or 10 cycles for the delegate call, and the range version can cost nothing compared to a hand-coded version because all of the range primitives are eligible for inlining. One of these two styles will do what you need w/o much trouble about 99.9% of the time.
dsimcha
Thanks, dsimcha. Using ranges looks very promising, I shall look it up.
Dmitry O_o