Search code examples
ddmd

What is a "yield return" equivalent in the D programming language?


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); 
}

Solution

  • 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.