On 03/09/2012 05:14 PM, Manu wrote:
On 9 March 2012 17:57, Timon Gehr <timon.g...@gmx.ch
<mailto:timon.g...@gmx.ch>> wrote:

    On 03/09/2012 04:38 PM, Manu wrote:

        On 9 March 2012 16:27, Timon Gehr <timon.g...@gmx.ch
        <mailto:timon.g...@gmx.ch>
        <mailto:timon.g...@gmx.ch <mailto:timon.g...@gmx.ch>>> wrote:

            On 03/09/2012 01:23 AM, Manu wrote:

                I can imagine syntax using parentheses, but I don't
        think I'm
                qualified
                to propose a robust syntax, I don't know enough about
        the finer
                details
                of the grammar.
                Perhaps if other people agree with me, they could
        present some
                creative
                solutions to the syntax?

                I imagine something like:
                auto (x, y) = func(); // specify auto for all results?
                float (x, y) = func(); // specify explicit type for all
        results?
                (int x, float y) = func; // explicitly type each result?


            This works, and Kenji Hara has already implemented appropriate
            parser extensions.

                int x; ... (x, float y) = func(); // assign to predeclared
                variable(/s)?
                (x, , z) = func(); // ignore the second result value
                (elimination of the

                second result's code path)


            Those two would work, but (x,y) = func(); conflicts with the
        comma
            operator. (I'd prefer (,) to be a tuple constructor though.)


        You think so? Within that context, I would think the coma could be
        reinterpreted however it likes. The usual use of the coma
        operator makes
        no sense in this context?


    void main(){
        int a,b;
        (a,b)=2;
        assert(a==0);
        assert(b==2);

    }


        These last 2 examples are what I see as being the most important
        part,
        and the precise reason that it SHOULDN'T be a tuple.


    You are probably confusing the tuple concept with a Phobos Tuple.

        The ability to
        directly assign results to explicit (existing) variables, and to
        ignore
        some/all of the return values, is a fundamental feature of the
        /concept/

        of return values universally.
        I see this as basically the whole point.
        Another example: (someStruct.x, y, , int err) = func();
        In this example, I assign the x result to a struct, y assigns to
        some
        existing local, we ignore z because we can (visually states our
        intent,
        would be hidden through use of a tuple), and we declare an int to
        capture a potential error in place.


    This is simple pattern matching.


I'm not sure what you mean by this?

        If we were abusing the tuple syntax, we would need additional lines
        following the call to assign the rvalues out to their appropriate
        places, which is unnecessary spaghetti.


    What you propose is tuple syntax.


What I mean is this:

retTuple = func();
someStruct.x = retTuple[0];
y = retTuple[1];
// retTuple[2] is ignored, but the intent is not clear in the code as it
was in my prior example, I like how my prior example makes this intent
explicit
int err = retTuple[3];

This is pretty horrible. Surely you can see why I want to be able to
arbitrarily assign the return values directly?
That's what I mean by 'abuse of the tuple syntax', but if that's not
what you mean, then show me an example of the usage of your suggestion?

There are two parts, syntax and semantics.

Semantics:
D is already able to express those:

template Tuple(T...){alias T Tuple;} // not the same as std.typecons.Tuple!

// function with multiple return values:
Tuple!(int,double) foo(int a, double b){
    Tuple!(int, double) result; // ok, _no imposed memory layout_
    result[0] = a;              // ok
    result[1] = a+b;              // ok
    return result;
}

Multiple return values are currently *disallowed explicitly*:
DMD sez: "Error: functions cannot return a tuple"

Just specify the ABI, implement the code gen, and we're done.

Moot point: built-in tuples auto-flatten inside comma-separated lists.

std.typecons.Tuple is a hack to circumvent the arbitrary "cannot return tuple from function" restriction as well as the auto-flattening. The problem is that it is implemented as a struct with a built-in tuple member. The fact that it is a struct imposes a memory layout. This is just a side-effect of attempting to address the other two issues. It is not something that is desirable.


Syntax:
Currently, there is just none. Tuples are a built-in types that cannot be created without a template that makes them accessible.

IMHO Ideally, it would look like this:


(int, double) foo(int a, double b) => (a, a+b);//Jonathan does not like this

void main(){
    (int, double) bar = (1,2.0);
    auto (x,y) = (1,2.0);
    bar = foo(x,y);
    (x,_) = foo(bar); // ignore y, assign x (bar auto-flattened)
    (_,y) = foo(bar); // ignore x, assign y (bar auto-flattened)

    x = 1, y = 2.0; // comma operator
    auto z = (x = 1, y = 2.0)[$-1]; // "comma operator"

    (int x, double y) foo = (1,2.0); // name the tuple fields
    static assert(is(typeof(foo.x==int)));
    static assert(is(typeof(foo.y==double)));

    bar = foo; // structural typing of tuples, field names don't matter
    foo = bar;

    (foo, bar) = (1, 2.0, 3, 4.0); // foo and bar auto-flattened
    assert(foo.x == 1 && foo.y == 2.0 && bar[0]==3 && bar[1] == 4.0);

MultiRange range; // a range with multiple element types, eg (int, double) front(){...}
    foreach((a,b); range){ ... }
}

But this would break existing code that uses the comma operator...
Another issue is that people would complain about auto-flattening all the time once built-in tuples get more accessible, even though it is not actually a problem. It would be just due to the fact that it does not occur in most other popular programming languages.


Reply via email to