On Tue, Jan 07, 2014 at 09:18:48PM +0100, Jacob Carlborg wrote: > On 2014-01-07 16:58, H. S. Teoh wrote: > > >Y'know, I've always wanted "trailing delegate syntax": > > > > func(x, y, z; p, q, r) { > > // body > > } > > > >gets translated into: > > > > func(p, q, r, (x, y, z) => /* body */); > > > >Since we already have UFCS, which translates a leading fragment into > >the first argument (x.func(y) --> func(x,y)), it seems perfectly > >reasonable to do something with the final argument too, like the > >above. > > > >This would allow one to implement, for example, foreach_reverse as a > >library function instead of a language keyword: > > > > void foreach_reverse(I, R)(R range, void delegate(I) dg) > > { > > ... > > dg(idx); > > ... > > } > > > > // Gets translated to: > > // foreach_reverse(range, (uint i) => /* body */); > > foreach_reverse (uint i; range) { > > ... // body > > } > > > > // And you can use UFCS too: > > range.foreach_reverse(uint i) { > > ... // body > > } > > Exactly, that's what it is for. Perhaps supporting an alias > parameter would be good as well, since those are inlined: > > void foo (alias dg) (); > > foo { > // body > } > > Translated to: > > foo!({ > // body > }); > > >I'm not holding my breath on this one, though. It's a rather big > >change and ultimately is just syntactic sugar. Maybe it can go on the > >list of features for D3... ;-) > > I've brought this up before. If I recall correctly, it didn't was > that much resistance as one could think. Although this was before we > had the lambda syntax. [...]
If you have a good motivating use case in favor of this addition that can be used in a DIP, I'd vote for it. 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 } // which gets translated into: foo!((i,j,k,...) { /* body */ })(a,b,c,...); 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); } EXTENDED EXAMPLE: void for_every_other(alias loopBody, R)(R range) if (is(typeof(loopBody(size_t.init, ElementType!R.init)))) { size_t i=0; while (!range.empty) { loopBody(i, range.front); range.popFront(); if (!range.empty) { range.popFront(); i += 2; } } } // Prints: // --- // 0: "a" // 2: "c" // 4: "e" // --- for_every_other (i, j; ["a", "b", "c", "d", "e", "f"]) { writefln("%s: %s", i, j); } T -- Error: Keyboard not attached. Press F1 to continue. -- Yoon Ha Lee, CONLANG