Multiple return values...

Manu turkeyman at gmail.com
Sat Mar 10 02:37:20 PST 2012


On 10 March 2012 06:16, Andrei Alexandrescu
<SeeWebsiteForEmail at erdani.org>wrote:

> On 3/9/12 3:59 PM, Timon Gehr wrote:
>
>> Yes, but we wouldn't have needed it if the built-in one would have been
>> considered sufficient.
>>
>
> The goal is considering the language sufficient for implementing a useful
> structure such as Tuple in a library. Same goes about associative arrays.


Well if the library Tuple is the official Tuple, then I'm back at square
one, and all my points I raised starting this thread stand.

- Returning it from a function is not efficient.
>>
>
> Implementation issue, if at all. Solving that will optimize the return of
> any structure in any D code.


I disagree, refer to the start of the thread, I argue that returning a
struct by value and returning multiple un-associated values is a
fundamentally different concept. The 2 don't relate in my mind, and
shouldn't try to be smashed together in one concept. This just convolutes
one or the other, depending which one the implementation favours.


> - It does not play very nicely with type deduction.
>>
>
> It plays by the rules enacted by the D programming language. If those
> aren't nice, there's a problem with them rules. If you like them rules but
> want "special" rules for templates, you're asking for magic. Magic smells.


Perhaps the type deduction rule when passing the results of a
multiple-return function to a template could be to implicitly collect into
Tuple only at _THAT_ point. But it could also just as readily be a syntax
error; multiple things passed into a slot meant to receive a single thing
is obviously a syntax error, and an explicit mechanism to collect the
multiple results into a Tuple to perform the pass-through is preferable by
my measure (Intent is explicit, and clearly written before your eyes).

- It has clumsy syntax and is therefore rarely used.
>>
>
> Then templates have clumsy syntax and therefore are rarely used.


This doesn't make sense to me, template syntax has nothing to do with it.
Munging a bunch of things together in order to perform a multi-return is
self-defeating. Why am I needing to write code to structurally&logically
associate these things? That defeats the initial premise. If I *want* to
return a Tuple, I will return a Tuple, and there is no discussion.


> Notably, there is no convenient unpacking syntax. Walter does not merge
>> the patches of Kenji Hara that would fix this because presumably he
>> fears it could get in the way of a more general solution.
>>
>
> This is because we need to think about that stuff to maximize its
> generality.


Any automated 'unpacking' syntax is really just syntactical sugar though...
it's not addressing the problem in a direct way.
The fact that you should need 'unpacking' in the first place means we've
already missed the point.

 This situation is neither particularly pragmatic nor pure enough. I'd
>> call it a wart.
>>
>
> I'd call it a great artifact. Love the Tuple (and the Drake).


I still fundamentally see a clear divide between a Tuple, which is a
deliberately structured association of multiple values, and 'multiple
return values' which is an explicit non-association of multiple returned
things.
You need to address that principle before I can begin to accept the idea of
abusing a structured tuple as a substitute for this important language
feature.

My analogy is the function argument list. You don't think of the arguments
you pass to a function as a Tuple (is it implemented internally in this
way? if so, it is well hidden, and perhaps similar magic can be done...)
You pass, TO a function, multiple un-associated values. They follow a well
understood calling convention (primitives in registers, byval structs
copied to the stack)
It should be possible in the language to express receiving multiple
un-associated values back from the function, in PRECISELY the same way, but
in reverse (primitives in registers, byval structs returned on the stack)

If I pass a structure TO a function by value, I know what happens, a copy
is written to the stack which the function expects to find there.
If I return a structure (Tuple) from a function, I expect precisely the
same behaviour. That is what I have written, that is what I expect the
language to do. We shouldn't mess with this.

I see serious ABI problems and confusion with 'optimising' byval structs to
behave in the way I want from multiple return values.
If I do this: func(byValStruct, intX, floatY, intZ);
What would happen under the 'optimised' call? byValStruct could potentially
hog all the argument registers the CPU has, and the following primitive
arguments may overflow to the stack. As a programmer, I do NOT expect this,
it would be a very nasty surprise.
Those primitive arguments will certainly be used within the function, which
means I've performed a (hidden) redundant store/load straight up. Also,
it's not clear whether the function has business with many/every single
value in the struct I'm passing, so I may very well be loading items from
the struct into wasted argument registers that are never used by the
function to satisfy this new calling convention. Everything about this is
inefficient.

This is unacceptable, but this is how the optimisation for multiple return
values via structured Tuples would have to work. I can't see how it could
work in any other way?

On 3/9/12 4:10 PM, Timon Gehr wrote:
>
>> (int, int) foo(int a, int b){return (a,b);}
>>
>> assert(foo(foo(foo(foo(1,2))))**==(1,2));
>>
>> (int, int) goo(int a, int b, int c){return (a+b, c);}
>>
>> assert(goo(foo(2,3),1) == (5,1));
>>
>
> This is a recipe for disaster because of the implicit expansion. Consider
> forwarding the result of foo to some template. Should the template take the
> tuple type, or automatically expand the tuple and accept individual values?


Perhaps it should just be a syntax error (squeezing multiple things into 1
slot).
That said, both approaches will be wanted under different circumstances. If
you don't like the syntax error, then I suggest the better approach would
be auto-expansion to individual values, and offer a simple method of *
explicitly *boxing multiple values expressed that way into a Tuple, which
will give you convenient access to both behaviours, and improve code
clarity (I don't like complex implicit things). The Tuple constructor must
surely be capable of this already?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20120310/d27a384f/attachment-0001.html>


More information about the Digitalmars-d mailing list