Programming in D – Tutorial and Reference
Ali Çehreli

Other D Resources

static foreach

We saw compile-time foreach earlier in the Tuples chapter. Compile-time foreach iterates the loop at compile time and unrolls each iteration as separate pieces of code. For example, given the following foreach loop over a tuple:

    auto t = tuple(42, "hello", 1.5);

    foreach (i, member; t) {
        writefln("%s: %s", i, member);
    }

The compiler unrolls the loop similar to the following equivalent code:

    {
        enum size_t i = 0;
        int member = t[i];
        writefln("%s: %s", i, member);
    }
    {
        enum size_t i = 1;
        string member = t[i];
        writefln("%s: %s", i, member);
    }
    {
        enum size_t i = 2;
        double member = t[i];
        writefln("%s: %s", i, member);
    }

Although being very powerful, some properties of compile-time foreach may not be suitable in some cases:

void main() {
    enum arr = [1, 2];
    // Executed at run time, not unrolled at compile time:
    foreach (i; arr) {
        // ...
    }
}
import std.meta;

// Attempting to define function overloads at module scope:
foreach (T; AliasSeq!(int, double)) {    // ← compilation ERROR
    T twoTimes(T arg) {
        return arg * 2;
    }
}

void main() {
}
Error: declaration expected, not foreach

static foreach is a more powerful compile-time feature that provides more control:

    static foreach (n; FibonacciSeries().take(10).filter!isEven) {
        writeln(n);
    }

The loop above would be unrolled as the following equivalent:

    writeln(0);
    writeln(2);
    writeln(8);
    writeln(34);
import std.meta;

static foreach (T; AliasSeq!(int, double)) {
    T twoTimes(T arg) {
        return arg * 2;
    }
}

void main() {
}

The loop above would be unrolled as its following equivalent:

    int twoTimes(int arg) {
        return arg * 2;
    }

    double twoTimes(double arg) {
        return arg * 2;
    }
import std.stdio;

void main(string[] args) {

theSwitchStatement:
    switch (args.length) {
        static foreach (i; 1..3) {
            case i:
                writeln(i);
                break theSwitchStatement;
        }

    default:
        writeln("default case");
        break;
    }
}

After the loop above is unrolled, the switch statement would be the equivalent of the following code:

    switch (args.length) {
    case 1:
        writeln(1);
        break;

    case 2:
        writeln(2);
        break;

    default:
        writeln("default case");
        break;
    }