On Wed, Jan 08, 2014 at 08:32:15AM +0100, Jacob Carlborg wrote: > On 2014-01-07 21:44, H. S. Teoh wrote: [...] > >I like the alias idea, so here's the revised proposal: > > > >1) Argumentless trailing-delegate syntax: > > > > // Given this declaration: > > void foo(alias dg)(); > > > > // We can write this: > > foo { > > // body > > } > > > > // which will get translated into: > > foo!({ /* body */ }); > > > >2) With arguments: > > > > // Given this declaration: > > void foo(alias dg, A...)(A args); > > > > // Or its non-template equivalent: > > void foo(alias dg)(A arg1, B arg2, C arg3, ...); > > > > // We can write this: > > foo(a,b,c,...) { > > // body > > } > > > > // which gets translated into: > > foo!({ /* body */})(a,b,c,...); > > > >3) With indexing arguments: > > > > // Given this declaration: > > void foo(alias dg, I..., A...)(A args) > > if (is(typeof(dg(I)))); > > > > // Or its non-template equivalent: > > void foo(alias dg)(A arg1, B arg2, C arg3, ...) { > > ... > > dg(i, j, k); > > ... > > } > > > > // We can write this: > > foo(i,j,k,... ; a,b,c,...) { > > // body > > } > > I would prefer to have the delegate arguments last.
The reason I wrote it this way is so that it parallels the foreach construction better: my_foreach (i; range) { ... } parallels: foreach (i; range) { ... } [...] > >EXAMPLE: > > > > void for_every_other(alias loopBody, R)(R range) > > if (is(typeof(loopBody(ElementType!R.init)))) > > { > > while (!range.empty) { > > loopBody(range.front); > > range.popFront(); > > if (!range.empty) > > range.popFront(); > > } > > } > > > > // Prints: > > // --- > > // 1 > > // 3 > > // 5 > > // --- > > for_every_other (i; [1,2,3,4,5,6]) { > > writeln(i); > > } > > If we instead have the delegate argument last UFCS still works: > > [1,2,3,4,5,6].for_every_other(i) { > writeln(i); > } > > Hmm. Actually, your example is more D like. I don't know which I > example I like best. [...] 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)); 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);`. 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 */ }); 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. 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: void pure_block(alias dg)() pure if (is(typeof(dg()))) { dg(); } void nothrow_block(alias dg)() nothrow if (is(typeof(dg()))) { dg(); } void safe_block(alias dg)() @safe if (is(typeof(dg()))) { dg(); } void main() { pure_block { // Whoopie! now we acquired a construct for // marking blocks of code pure! } nothrow_block { // And we can have multiple such blocks in a // single function. } safe_block { // Now I'm just showing off. :P } } T -- Curiosity kills the cat. Moral: don't be the cat.