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

Reply via email to