Multiple return values...

Timon Gehr timon.gehr at gmx.ch
Fri Mar 9 10:16:19 PST 2012


On 03/09/2012 05:14 PM, Manu wrote:
> On 9 March 2012 17:57, Timon Gehr <timon.gehr at gmx.ch
> <mailto:timon.gehr at gmx.ch>> wrote:
>
>     On 03/09/2012 04:38 PM, Manu wrote:
>
>         On 9 March 2012 16:27, Timon Gehr <timon.gehr at gmx.ch
>         <mailto:timon.gehr at gmx.ch>
>         <mailto:timon.gehr at gmx.ch <mailto:timon.gehr at 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.




More information about the Digitalmars-d mailing list