On 2014-01-08 19:04, H. S. Teoh wrote:

The reason I wrote it this way is so that it parallels the foreach
construction better:

        my_foreach (i; range) {
                ...
        }

parallels:

        foreach (i; range) {
                ...
        }

I guessed that.

Keep in mind that the identifier list before the ';' is actually the
delegate's parameter list, it's not passing anything in. They are
placeholders for what the function will pass to the delegate. So:

        my_foreach (i,j ; range) {
                writeln(i + j);
        }

actually means:

        my_foreach(range, (i,j) => writeln(i + j));

Yeah, I know.

and my_foreach could be implemented something like this:

        void my_foreach(alias dg, R)(R range)
                if (is(typeof(dg(size_t.init, ElementType!R.init))))
        {
                size_t idx = 0;
                while (!range.empty) {
                        // N.B.: calls dg with i = idx, j = range.front
                        dg(idx, range.front);

                        range.popFront();
                        idx++;
                }
        }


If we go by this, then UFCS should still work:

        range.my_foreach(i,j) { /* body */ }

should be translated to:

        my_foreach(i, j ; range) { /* body */ }

which in turn translates to:

        my_foreach!((i, j) { /* body */ })(range);

In the first case, there is no ambiguity with `range.my_foreach(i,j);`,
which should translate to `my_foreach(range,i,j);`, because the presence
of the trailing code block without an intervening ';' makes it clear
that the above is intended, rather than `my_foreach(range,i,j);`.

Didn't think of that.

In fact, we can already almost get the desired syntax in the current
language:

        /* Current D already supports this: */
        range.my_foreach!((i,j) {
                /* body */
        });

Almost ;)

which isn't that much different from the proposed syntactic sugar:

        range.my_foreach(i,j) {
                /* body */
        }

We're just saving on the '!', ';', and an extra pair of parentheses.

It quickly get clumsy when you need to pass regular arguments to the function:

void foo (alias dg) (int a, int b);

foo!((i, j) {
    // body
})(1, 2);

Not pretty.

I guess the only real advantage is that we get to imitate built-in
foreach syntax. E.g., if we use the form with arguments but no indexing
arguments, we can pretend to be an if-statement:

        // (Whatever "dynamic if" means...)
        void dynamic_if(alias dg)(bool cond)
                if (is(typeof(dg())))
        {
                // Haha, we're just wrapping the built-in 'if' cuz we
                // can.
                if (cond) dg();
        }

        int x;
        dynamic_if (x==0) {
                writeln("Boo yah!");
        }

Or if we use the argumentless form to implement custom block constructs:

BTW, what do you think about not needing braces if the delegate body only contains a single statement, like with regular statements:

dynamic_if (x==0)
    writeln("foo");

With the alias syntax, I'm wondering if the compiler will have any problem with that you can pass almost anything to an alias parameter and not just a delegate.

--
/Jacob Carlborg

Reply via email to