Multiple return values...

Manu turkeyman at gmail.com
Thu Mar 8 15:28:16 PST 2012


On 9 March 2012 00:29, Mantis <mail.mantis.88 at gmail.com> wrote:

> 08.03.2012 22:08, Manu пишет:
>
>  I find myself really wishing for proper multiple return values almost
>> every day, particularly when I work with maths heavy code, and especially
>> for efficiently returning error codes in functions I'd rather not throw
>> from.
>> Many maths-y functions return some sort of pair; intersections return
>> (ray, t) or something of that type.
>> I'm finding HEAPS of SIMD functions want to return pairs (unpacks in
>> particular): int4 (low, hight) = unpack(someShort8);
>> Currently I have to duplicate everyting: int4 low =
>> unpackLow(someShort8); int4 high = unpackHigh(someShort8);
>> I'm getting really sick of that, it feels so... last millennium.
>>
>> The point of 'proper' multiple return values is to return each value in
>> registers, in its own register type, using exactly the same register
>> assignment pattern as when passing args TO functions.
>> I don't think this causes any side effects to the ABI, since the arg
>> registers are already volatile across function calls in the first place.
>> It just means that the returned-to function can find its return values
>> already conveniently in an appropriate register, avoiding memory access.
>>
>> People argue I should return a tuple, but this isn't really the same, it
>> has hidden implications that complicate the optimisation potential. For
>> instance, tuples have an implicit structure/memory layout which can't be
>> ignored, whereas return values don't have memory allocated, ie, you can't
>> take the address of a return value without first assigning it to some local
>> syntactically.
>> The implementation of efficient tuple return values would be much more
>> complicated I would imagine too, and the rules are less clear; I can't
>> intuitively presume what behaviour returning a tuple of different things
>> should actually have in terms of register assignment. I also know precisely
>> how multiple return values should work, because it is exactly the same as
>> passing arguments to the function, but in reverse.
>>
>> ... just saying :)
>>
>
> I'd like to see this as a part of tuple improvement, since tuples may hold
> additional compile-time information. This would make it possible to write
> efficient code, and at the same time have the ability to reference tuple
> components by name rather than position. For example:
> {
>    auto t = getSomeTuple(...); // returns Tuple!(float, "x", float, "y"),
> no actual assignment is made
>    someVar = t.x^^2 + t.y^^2; // t.x and t.y are just aliases for st1 and
> st0
> }
>
> With a tuple unpacking syntax suggested by bearophile, this would be nicer
> than any distinct multiple return values syntax, IMO.
>

The problem is, that approach feels like a double negative to me. A tuple
is fundamentally a structure, returned by value. Implementing hacks to
subvert the standard behaviour of returning a structure by value is
unintuitive for a start, and you also lose the ability to *actually* return
a structure by value should that be what you intend.
You're sacrificing a well defined, 'properly' implemented mechanic
to imitate something the language simply can't express. I just think that's
the wrong way to go about it.

Let me try and make my case as I see it...

These are 2 distinct concepts, returning multiple values, and returning a
struct by value.

Returning a structure by value is currently well defined, and behaves as
any same programmer would expect; it is written to the stack with memory
layout according to the STRUCTURE. This is true for a tuple, and it works
as one expects. I have no issue here. If you return a tuple, you SHOULD be
able to take the pointer of the first item, perform some arithmetic, and
address some other struct member. It is a struct, it ought to behave like
one, precisely as any programmer will expect.

By contrast, multiple return values are quite the opposite. They are
explicitly NON-STRUCTURED. These serve a totally different purpose; to
return multiple unstructured things from a function.
Imagine an inline function which returns 2 results, only one of which is
captured. It is easy and intuitive to eliminate the code path leading to
the ignored result. Not so simple if you're returning structured data,
because it could be indirectly addressed.
In this case, using an explicit syntax to perform this specific task
doesn't suffer from the implicit problems associated with subverting the
structure syntax (what to do about memory layout/pointer arithmetic?
reserve stack space and generate code to store implicitly? ick!), but it
also clearly states the programmers intent, and also clearly communicates a
presumed behaviour. The presumption in this case is that multiple return
values would follow the exact same set of rules as passing multiple args TO
a function, but in reverse.

Both operations seem useful and important in their own ways, they are also
both distinct operations, and they both warrant an expression in the
language. Returning a tuple if perfect how it is, it is just not what I
want to do in cases like those I list in my OP.

How is any programmer supposed to intuitively assume that returning a tuple
by value would behave in that way? And how are you supposed to trust it?
It's an abuse of concept and syntax. It seems like a convolution that could
only possibly confuse people, they are conceptually quite different things,
and shouldn't be lumped into the same syntax for my money.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20120309/2f29ce2a/attachment-0001.html>


More information about the Digitalmars-d mailing list