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