220 18239 <22a4d6a5-f6f1-4ed1-9ec9-743c32173f81@isocpp.org> article
Path: news.gmane.org!not-for-mail
From: Matthew Fioravante <fmatthew5876@gmail.com>
Newsgroups: gmane.comp.lang.c++.isocpp.proposals
Subject: Re: Re: Core Language feature: Multiple assignments
 from multiple return values via tuple
Date: Wed, 27 May 2015 08:11:34 -0700 (PDT)
Lines: 1101
Approved: news@gmane.org
Message-ID: <22a4d6a5-f6f1-4ed1-9ec9-743c32173f81@isocpp.org>
References: <69a59613-6504-466a-9878-786653d6087f@isocpp.org> <4498da2a-af3a-457d-9bf7-e8bb3721d6b9@isocpp.org> <mk2dns$s02$1@ger.gmane.org> <6ea4a1dc-bfb4-4219-93ea-606619a77c53@isocpp.org> <mk2g93$6j5$1@ger.gmane.org> <71a799fc-1897-4c43-adc6-5d26267688bb@isocpp.org> <e41cd575-e64e-4d96-821f-5c6237371ac3@isocpp.org> <500d24fe-73ba-439a-ac53-aeaa7919111e@isocpp.org> <32801228-1faf-4b73-8da1-9c8ce5bcb9ae@isocpp.org> <0b91248a-1994-4127-932e-9e1d97edadb2@isocpp.org> <ae452ecd-fcf2-49c5-8df8-e15687ebbbe0@isocpp.org>
 <62FE5462-BE3F-4C9E-B03D-322CB0CFF753@gmail.com>
Reply-To: std-proposals@isocpp.org
NNTP-Posting-Host: plane.gmane.org
Mime-Version: 1.0
Content-Type: multipart/mixed; 
	boundary="----=_Part_173_2103744840.1432739494049"
X-Trace: ger.gmane.org 1432739499 6404 80.91.229.3 (27 May 2015 15:11:39 GMT)
X-Complaints-To: usenet@ger.gmane.org
NNTP-Posting-Date: Wed, 27 May 2015 15:11:39 +0000 (UTC)
To: std-proposals@isocpp.org
Original-X-From: std-proposals+bncBDELF54RTIGRBJV5S6VQKGQEA6TA3ZA@isocpp.org Wed May 27 17:11:38 2015
Return-path: <std-proposals+bncBDELF54RTIGRBJV5S6VQKGQEA6TA3ZA@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-ig0-f199.google.com ([209.85.213.199])
	by plane.gmane.org with esmtp (Exim 4.69)
	(envelope-from <std-proposals+bncBDELF54RTIGRBJV5S6VQKGQEA6TA3ZA@isocpp.org>)
	id 1YxczY-00053D-2o
	for gclcip-std-proposals@m.gmane.org; Wed, 27 May 2015 17:11:36 +0200
Original-Received: by igbgg1 with SMTP id gg1sf35822245igb.1
        for <gclcip-std-proposals@m.gmane.org>; Wed, 27 May 2015 08:11:35 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=20120113;
        h=date:from:to:message-id:in-reply-to:references:subject:mime-version
         :content-type:x-original-sender:reply-to:precedence:mailing-list
         :list-id:list-post:list-help:list-archive:list-subscribe
         :list-unsubscribe;
        bh=puPbyyrnl+XALOlPd+3JEYpCmAd/FhYtXGZ3i6JJNuo=;
        b=HcIjXtfbT5boB3pTtAgbtl/zy3/JVkcXffgkN4npeMy+cCyktmXoh7YN/mqXxw4pys
         /WerLnzMZwIuA8cBLQu6j1Y4uvtA+kq+1/CpFi1o+bM+7NDUMtohilvSxETXg+lpt663
         ZDWStnZjAQ3kfDTM45u2CMsI8UIzrEtiKgNpbIru/xxYdupVnmB8tliVRckhluPGgn6M
         7aHb5DkUpupK79X97tokVrM3bi+Zub8QCp09WaVClJKB9tzyXx73L1PqwiZimIG4J5e/
         rRf0VPNA4zdGOA50Hwwc+23qXLqashdf37Xk0yhiwkxFoXG1mWSLHOJSQzr2AfTV6a5l
         KI+w==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20130820;
        h=x-gm-message-state:date:from:to:message-id:in-reply-to:references
         :subject:mime-version:content-type:x-original-sender:reply-to
         :precedence:mailing-list:list-id:list-post:list-help:list-archive
         :list-subscribe:list-unsubscribe;
        bh=puPbyyrnl+XALOlPd+3JEYpCmAd/FhYtXGZ3i6JJNuo=;
        b=Yx/XqTBAc4wfHkYH0c+HqaP2m602s2zisB6a4e7LZl8p2Air1ysPilyiLEz2rFFOSN
         z5cPZqchqcKN0QSiFXRTpVdAR6kDPKsWzNJKNDYo3siX5M+Ju5kcMO4k9Fe4ydeszSOp
         eWgCYW/m3cGnDkXju/YnXEXVagzPjOyIXx+pEIDlp0j+z0EyTRUUl2a70ZEQMMfeGawf
         cYG2t10+7hdBMbCww9sah0GEHeY3gzg1qrKVwjGhtgg/fZmPGpQ0Wbi9cNFcLkfRRwWq
         lrFcXOkRIm7ZEpuzNb8y0upwOv84xVekwqzKeoBsYX3riGxr8dyNA3sGz0jVESOBS1aY
         cG1w==
X-Gm-Message-State: ALoCoQkg1DFtxbu02Gjiz5CODAOOAmXCOW3KWPg7QNU/35S9iFbpiimB+pa3raFTCYRmGM20DDLX
X-Received: by 10.42.129.20 with SMTP id o20mr4245177ics.19.1432739495229;
        Wed, 27 May 2015 08:11:35 -0700 (PDT)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.140.109.71 with SMTP id k65ls221854qgf.48.gmail; Wed, 27 May
 2015 08:11:34 -0700 (PDT)
X-Received: by 10.140.97.7 with SMTP id l7mr410970qge.0.1432739494513;
        Wed, 27 May 2015 08:11:34 -0700 (PDT)
In-Reply-To: <62FE5462-BE3F-4C9E-B03D-322CB0CFF753@gmail.com>
X-Original-Sender: fmatthew5876@gmail.com
Precedence: list
Mailing-list: list std-proposals@isocpp.org; contact std-proposals+owners@isocpp.org
List-ID: <std-proposals.isocpp.org>
X-Google-Group-Id: 399137483710
List-Post: <http://groups.google.com/a/isocpp.org/group/std-proposals/post>, <mailto:std-proposals@isocpp.org>
List-Help: <http://support.google.com/a/isocpp.org/bin/topic.py?topic=25838>, <mailto:std-proposals+help@isocpp.org>
List-Archive: <http://groups.google.com/a/isocpp.org/group/std-proposals/>
List-Subscribe: <http://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>,
 <mailto:std-proposals+subscribe@isocpp.org>
List-Unsubscribe: <mailto:googlegroups-manage+399137483710+unsubscribe@googlegroups.com>,
 <http://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>
Xref: news.gmane.org gmane.comp.lang.c++.isocpp.proposals:18239
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/18239>

------=_Part_173_2103744840.1432739494049
Content-Type: multipart/alternative; 
	boundary="----=_Part_174_1468761672.1432739494049"

------=_Part_174_1468761672.1432739494049
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable



On Wednesday, May 27, 2015 at 3:43:10 AM UTC-4, Nicol Bolas wrote:

>
> In Lua, you don't need special syntax for returning or capturing multiple=
=20
> values. And quite frankly, I see no reason why you should:
>
> function foo()
>   return 1, 2, 3 --Returns a sequence of 3 values.
> end
>
> function bar()
>   return {1, 2, 3} --Returns a single table, containing 3 values
> end
>
> local x, y, z =3D foo() --Declares 3 local variables, initializing them w=
ith=20
> 3 values from the function.
>
> local w =3D {foo()} --Stores the sequence of values returned from `foo` i=
n=20
> a table (aka: array)
>
> local a =3D bar() --Stores the table
>
> local comp =3D bar(foo()) --The sequence is passed to `bar` as 3 paramete=
rs.
>
> local comp2 =3D bar(bar()) --A single parameter is passed to the outer `b=
ar`
> .
>
> local comp3 =3D bar(unpack(bar())) --Unpacks the array into the outer `ba=
r`'s=20
> parameters
>
> I find that much more reasonable and consistent than the Python syntax.=
=20
> There is a distinction between a sequence of values and a data structure.=
=20
> `foo` and `bar` may be "conceptually" the same, but functionally they're=
=20
> different. One returns a sequence of values, the other returns a table. I=
f=20
> you need to convert a table into a sequence of values, you call `unpack`.=
=20
> If you need to convert a sequence of values into a table, you create a=20
> table with it.
>
> Sequences of values in Lua are ephemeral; if you want to store the=20
> sequence and preserve it as a sequence, you stick it in a table. But if y=
ou=20
> just want to compose functions, store values, and the like, you use the=
=20
> sequence as is.
>
> If C++ is going to pattern its functionality off of something, I'd much=
=20
> rather Lua's proper MRV syntax than Python's MRVs-as-arrays (I assume the=
=20
> () syntax is creating an array of some kind).
>

We still need a special "unpacking" syntax to bind the multi return values=
=20
to variables because the comma operator is already taken and not sufficient=
=20
for this task. The following looks very confusing and it doesn't even=20
account for multiple return values of different types. It also doesn't let=
=20
us assign return values directly to pre-existing variables.

[int,int,int] foo();
int bar();
//Initializes x, y, z using foo's return values??
int x, y, z =3D foo();
//Initializes only c using bar's() return value and leaves a and b=20
uninitialized
int a, b, c =3D bar();
=20

We could allow using auto here:
[int,long,double] foo();
auto x, y, z =3D foo(); //x is int, y is long, z is double

But this still doesn't allow us to specify cv and ref qualifiers for the=20
individual variables.
=20

>
> =20
>>
>>
>>> As was stated earlier, doing it this way would be a huge change that=20
>>>> likely would never make it past the committee.
>>>>
>>>
>>> But it's the right way to do it. And quite frankly, we don't need=20
>>> multiple return values so badly that we should do it the wrong way just=
 to=20
>>> have *some* convenient way to do it.
>>>
>>> Some people use tuples a lot (some might say to the point of overuse).=
=20
>>> But you shouldn't steal potentially useful syntax from those C++=20
>>> programmers who don't use them.=20
>>>
>>
>> Programmers who have no interest in tuple itself can just use the syntax=
=20
>> to return multiple values and unpack them at the call site. They don't h=
ave=20
>> to care that tuple (or something tuple like) is used to accomplish this.
>>
>
> Except that they have to pay the cost for it. Consider something simple=
=20
> like this:
>
> auto single_value()
> {
>   std::string a =3D ...;
>   return a;
> }
>
> auto multi_value()
> {
>   std::string a =3D ...;
>   std::vector b =3D ...;
>   return [a; b];
> }
>
> `single_value` is subject to copy elision, so you should feel no problem=
=20
> with using it. Even with a small-string-optimized std::string class, you=
=20
> will get the maximum possible performance if you're using the result to=
=20
> initialize an object.
>
> With language-level multiple return values, `multi_value` would be able t=
o=20
> operate under the same principle. `a` and `b` would be considered return=
=20
> values, and they would each be separately subject to elision.
>
> With your way, that's just not possible. If that syntax creates a `tuple`=
,=20
> then it must copy or move initialize the elements of that `tuple`. So eve=
n=20
> though the `tuple` itself is subject to elision, the creation of it is no=
t.
>

So whats stopping someone from writing a proposal to allow copy/move=20
elision in your multi_value() example? Just because it can't happen now=20
doesn't mean we can't change the standard. Multi return values would be a=
=20
primary use case for such a proposal.


> =20
>>
>>> Syntax is a precious commodity, which once apportioned, cannot be taken=
=20
>>> back.
>>>
>>> It should also be noted that reflection, with the full ability to=20
>>> compile-time inspect and generate types with full syntax (including=20
>>> variable names) makes tuples... a dubious proposition for the future of=
=20
>>> C++. With reflection, you can index a struct by number. With reflection=
,=20
>>> you can take any typelist and build an honest-to-God struct out of it=
=20
>>> (which can be standard layout and such).
>>>
>>> In short, it is entirely possible that tuples will become obsolete, thu=
s=20
>>> also obsoleting this kind of syntax. So let's not have another std::bin=
d=20
>>> happen here...
>>>
>>
>> [int,long,double] foo();
>> auto x =3D foo();
>>
>> Ok, if tuple is out then what is decltype(x) in the above example doing=
=20
>> things your way?
>>
>
> There are two defensible answers to this:
>
> 1) A compilation error. You called a function that returns 3 things, but=
=20
> you only captured one. That suggests you weren't paying attention.
>
> 2) `int`. The other two types are dropped on the floor.
>
> #2 is probably the way to go. Any sort of aggregate object type is not=20
> even up for discussion.
>

Then I should also ask you how do you plan on capturing the multiple=20
values? Using a syntax similar to the one I proposed?

This looks bad:
[int,float] foo();
[auto x; auto y] =3D foo(); //Ok captures into x and y
[auto x; void] =3D foo(); //Ok captures first into x, throws away second
auto x =3D foo(); //Captures only first??

The last line there looks like an easy recipe for bugs, especially in=20
generic code. I would suggest making it a compiler error.

Also what if I want to save the sequence so that I can forward it multiple=
=20
times?
Using your approach, I might suggest allowing auto... to capture all of the=
=20
return values so that they can be forwarded along. This could work just=20
like a variadic template parameter pack.

void foo(int, float);
[int, float] bar();

auto... x =3D bar();
foo(x...);
foo(x...);

But we still have the generic code problems that Miro brought up.
=20

>
> Multiple return values means *multiple return values*, not "pack multiple=
=20
> values into some kind of object and unpack them later".
> =20
>
>> Another kind of typelist which is standard layout compatible? Or are we=
=20
>> no longer able to capture all of the return values into one object?
>>
>
> If you want to capture them all in an object, you just ask for it:
>
> auto x =3D make_tuple(foo());
>
> That is neither hard nor particularly verbose. You can even stick them in=
=20
> an array, if all of the returned values are of the same type:
>
> auto x =3D make_array(foo());
>
>
These require copy/move. In your example, unpacking is free (no-op) and=20
packing requires a copy/move. In my example unpacking is free (using=20
references) and packing is also free, assuming you want to continue using=
=20
the pack type returned by the function.=20
=20

> Or in an arbitrary data structure:
>
> auto x =3D std::vector<Type>{foo()};
>
> But most people using multiple return values don't capture them in a big=
=20
> object, so we don't make the syntax optimal for that case.
>

Its not uncommon. Every class that has multiple "values" (e.g=20
unordered_map)  will be returning them in a pack using its default=20
iterators so that one can write a simple range for loop.
=20

>
> If not using tuple, can you explain in a bit more detail how your propose=
d=20
>> solution would actually work?
>>
>
> The details of how it works are more or less the way Lua works.
>
> In C++ parlance, the notion of a "sequence of values" would be a=20
> construct. It would *not* necessarily be an "expression", in the same way=
=20
> that a braced-init-list is not an expression. Since it's a new construct,=
=20
> you can give it whatever properties you want.
>
> Functions can return sequences of values, with the sequence as a full par=
t=20
> of its return type. Using the sequence initialization syntax, you can=20
> initialize/assign multiple variables to a sequence of values. If a sequen=
ce=20
> of values is given to a function argument list, the values are placed in=
=20
> that list as arguments. If the sequence of values is used in any other ki=
nd=20
> of expression, then it resolves down to the first element of that sequenc=
e=20
> of values.
>
> Initialization/assignment of variables through a sequence would work=20
> element by element, in order from left to right.
>

I would suggest maybe piggybacking off of varadic template parameter packs=
=20
(If they can fit into this feature) instead of inventing a yet another=20
brand new thing which is only used for multiple return values which itself=
=20
does not show up very often.

You mentioned reflection before. I believe with reflection, we can achieve=
=20
even better interfaces if we designed this MRV feature around unpacking=20
collections of objects.
For example, imagine if we could unpack a pod struct like this (implemented=
=20
using reflection):

struct kv {
string key;
int value;
};

kv kv;
[auto k; auto v] =3D kv;

Why is this so great? Here is an example:

template <typename K, typename V>
class HashMap {
public:
  struct kv { K key; V value; };
  class iterator : public std::iterator<std::bidirectional_iterator_tag,kv>=
=20
{ /* ... */ };
  //...
};

HashMap hashmap =3D /* something */;

//Iterate using kv struct (more descriptive than pair)
for(auto& kv: hashmap) {
  doSomething(kv.key, kv.value);
}

//Iterate by unpacking the kv struct first
for([auto& key; auto& value]: hashmap) {
  doSomething(key, value);
}

//Iterate over only the keys
for([auto& key; void]: hashmap) {}

//Iterate over only the values
for([void; auto& value]: hashmap) {}

If the MRV feature is designed around unpacking collections of objects,=20
then we can get interfaces like this for free from reflection. All 4=20
example loops are enabled without any additional work by the author of=20
HashMap.=20

If MRV is designed using sequences, then the class author has to provide=20
separate iterators for returning an MRV sequence and also returning a pack=
=20
in the default iterators. Class designers are already overburdened with=20
boilerplate for writing type trait tags, iterator types, copy/move=20
constructors, comparison operators, swap operator, etc..=20

The Lua way of doing things might be elegant, but lua is also a very simple=
=20
language. It doesn't have the same features and restrictions of C++ and I'm=
=20
not sure yet if that approach would be the best way.

On Wednesday, May 27, 2015 at 4:51:58 AM UTC-4, Miro Knejp wrote:
>
> I assume Matthew=E2=80=99s point comes from dealing with template code.
>
> template<class F>
> ??? contrived_example(F f) {
>     return f();
> }
>
> The author would probably expect that ??? can be plain =E2=80=9Cauto=E2=
=80=9D, implying=20
> =E2=80=9Cin some places auto can expand to multiple types=E2=80=9D. Then =
there=E2=80=99s the point=20
> of what generic code would require to do to consistently capture the retu=
rn=20
> value(s) of a Callable without knowing if there are one or multiple retur=
n=20
> values.
>
> template<class F>
> void contrived_example2(F f) {
>     ??? x =3D f();
>     ...
> }
>
> Should ??? be something that can potentially capture a single or multiple=
=20
> values depending on the initialization? If so what can be done with x dow=
n=20
> the pipeline? Or is a concept necessary to overload contrived_example2 fo=
r=20
> functions with single or multiple return values? Is template code forced=
=20
> into packing every Callable=E2=80=99s invocation into make_tuple() just i=
n case it=20
> might return multiple values?
>
>
These are very good questions. If multi return is just sugar for returning=
=20
a pack type, then generic code works just fine without any issue. If not,=
=20
then we have a lot of questions to answer.=20

--=20

---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.

------=_Part_174_1468761672.1432739494049
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><br>On Wednesday, May 27, 2015 at 3:43:10 AM UTC-4, Ni=
col Bolas wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin: 0;ma=
rgin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=
=3D"ltr"><br><div>In
 Lua, you don't need special syntax for returning or capturing multiple=20
values. And quite frankly, I see no reason why you should:<br><br><div styl=
e=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);border=
-style:solid;border-width:1px;word-wrap:break-word"><code><div><span style=
=3D"color:#008">function</span><span style=3D"color:#000"> foo</span><span =
style=3D"color:#660">()</span><span style=3D"color:#000"><br>&nbsp; </span>=
<span style=3D"color:#008">return</span><span style=3D"color:#000"> </span>=
<span style=3D"color:#066">1</span><span style=3D"color:#660">,</span><span=
 style=3D"color:#000"> </span><span style=3D"color:#066">2</span><span styl=
e=3D"color:#660">,</span><span style=3D"color:#000"> </span><span style=3D"=
color:#066">3</span><span style=3D"color:#000"> </span><span style=3D"color=
:#660">--</span><span style=3D"color:#606">Returns</span><span style=3D"col=
or:#000"> a sequence of </span><span style=3D"color:#066">3</span><span sty=
le=3D"color:#000"> values</span><span style=3D"color:#660">.</span><span st=
yle=3D"color:#000"><br></span><span style=3D"color:#008">end</span><span st=
yle=3D"color:#000"><br><br></span><span style=3D"color:#008">function</span=
><span style=3D"color:#000"> bar</span><span style=3D"color:#660">()</span>=
<span style=3D"color:#000"><br>&nbsp; </span><span style=3D"color:#008">ret=
urn</span><span style=3D"color:#000"> </span><span style=3D"color:#660">{</=
span><span style=3D"color:#066">1</span><span style=3D"color:#660">,</span>=
<span style=3D"color:#000"> </span><span style=3D"color:#066">2</span><span=
 style=3D"color:#660">,</span><span style=3D"color:#000"> </span><span styl=
e=3D"color:#066">3</span><span style=3D"color:#660">}</span><span style=3D"=
color:#000"> </span><span style=3D"color:#660">--</span><span style=3D"colo=
r:#606">Returns</span><span style=3D"color:#000"> a single table</span><spa=
n style=3D"color:#660">,</span><span style=3D"color:#000"> containing </spa=
n><span style=3D"color:#066">3</span><span style=3D"color:#000"> values<br>=
</span><span style=3D"color:#008">end</span><span style=3D"color:#000"><br>=
<br></span><span style=3D"color:#008">local</span><span style=3D"color:#000=
"> x</span><span style=3D"color:#660">,</span><span style=3D"color:#000"> y=
</span><span style=3D"color:#660">,</span><span style=3D"color:#000"> z </s=
pan><span style=3D"color:#660">=3D</span><span style=3D"color:#000"> foo</s=
pan><span style=3D"color:#660">()</span><span style=3D"color:#000"> </span>=
<span style=3D"color:#660">--</span><span style=3D"color:#606">Declares</sp=
an><span style=3D"color:#000"> </span><span style=3D"color:#066">3</span><s=
pan style=3D"color:#000"> </span><span style=3D"color:#008">local</span><sp=
an style=3D"color:#000"> variables</span><span style=3D"color:#660">,</span=
><span style=3D"color:#000"> initializing them </span><span style=3D"color:=
#008">with</span><span style=3D"color:#000"> </span><span style=3D"color:#0=
66">3</span><span style=3D"color:#000"> values </span><span style=3D"color:=
#008">from</span><span style=3D"color:#000"> the </span><span style=3D"colo=
r:#008">function</span><span style=3D"color:#660">.</span><span style=3D"co=
lor:#000"><br><br></span><span style=3D"color:#008">local</span><span style=
=3D"color:#000"> w </span><span style=3D"color:#660">=3D</span><span style=
=3D"color:#000"> </span><span style=3D"color:#660">{</span><span style=3D"c=
olor:#000">foo</span><span style=3D"color:#660">()}</span><span style=3D"co=
lor:#000"> </span><span style=3D"color:#660">--</span><span style=3D"color:=
#606">Stores</span><span style=3D"color:#000"> the sequence of values retur=
ned </span><span style=3D"color:#008">from</span><span style=3D"color:#000"=
> </span><span style=3D"color:#080">`foo`</span><span style=3D"color:#000">=
 </span><span style=3D"color:#008">in</span><span style=3D"color:#000"> a t=
able </span><span style=3D"color:#660">(</span><span style=3D"color:#000">a=
ka</span><span style=3D"color:#660">:</span><span style=3D"color:#000"> arr=
ay</span><span style=3D"color:#660">)</span><span style=3D"color:#000"><br>=
<br></span><span style=3D"color:#008">local</span><span style=3D"color:#000=
"> a </span><span style=3D"color:#660">=3D</span><span style=3D"color:#000"=
> bar</span><span style=3D"color:#660">()</span><span style=3D"color:#000">=
 </span><span style=3D"color:#660">--</span><span style=3D"color:#606">Stor=
es</span><span style=3D"color:#000"> the table<br><br></span><span style=3D=
"color:#008">local</span><span style=3D"color:#000"> comp </span><span styl=
e=3D"color:#660">=3D</span><span style=3D"color:#000"> bar</span><span styl=
e=3D"color:#660">(</span><span style=3D"color:#000">foo</span><span style=
=3D"color:#660">())</span><span style=3D"color:#000"> </span><span style=3D=
"color:#660">--</span><span style=3D"color:#606">The</span><span style=3D"c=
olor:#000"> sequence </span><span style=3D"color:#008">is</span><span style=
=3D"color:#000"> passed to </span><span style=3D"color:#080">`bar`</span><s=
pan style=3D"color:#000"> </span><span style=3D"color:#008">as</span><span =
style=3D"color:#000"> </span><span style=3D"color:#066">3</span><span style=
=3D"color:#000"> parameters</span><span style=3D"color:#660">.</span><span =
style=3D"color:#000"><br><br></span><span style=3D"color:#008">local</span>=
<span style=3D"color:#000"> comp2 </span><span style=3D"color:#660">=3D</sp=
an><span style=3D"color:#000"> bar</span><span style=3D"color:#660">(</span=
><span style=3D"color:#000">bar</span><span style=3D"color:#660">())</span>=
<span style=3D"color:#000"> </span><span style=3D"color:#660">--</span><spa=
n style=3D"color:#000">A single parameter </span><span style=3D"color:#008"=
>is</span><span style=3D"color:#000"> passed to the outer </span><span styl=
e=3D"color:#080">`bar`</span><span style=3D"color:#660">.</span><span style=
=3D"color:#000"><br><br></span><span style=3D"color:#008">local</span><span=
 style=3D"color:#000"> comp3 </span><span style=3D"color:#660">=3D</span><s=
pan style=3D"color:#000"> bar</span><span style=3D"color:#660">(</span><spa=
n style=3D"color:#000">unpack</span><span style=3D"color:#660">(</span><spa=
n style=3D"color:#000">bar</span><span style=3D"color:#660">()))</span><spa=
n style=3D"color:#000"> </span><span style=3D"color:#660">--</span><span st=
yle=3D"color:#606">Unpacks</span><span style=3D"color:#000"> the array </sp=
an><span style=3D"color:#008">into</span><span style=3D"color:#000"> the ou=
ter </span><span style=3D"color:#080">`bar`'s parameters<br></span></div></=
code></div><br>I
 find that much more reasonable and consistent than the Python syntax.=20
There is a distinction between a sequence of values and a data=20
structure. `foo` and `bar` may be "conceptually" the same, but=20
functionally they're different. One returns a sequence of values, the=20
other returns a table. If you need to convert a table into a sequence of
 values, you call `unpack`. If you need to convert a sequence of values=20
into a table, you create a table with it.<br><br>Sequences of values in=20
Lua are ephemeral; if you want to store the sequence and preserve it as a
 sequence, you stick it in a table. But if you just want to compose=20
functions, store values, and the like, you use the sequence as is.<br><br>I=
f
 C++ is going to pattern its functionality off of something, I'd much=20
rather Lua's proper MRV syntax than Python's MRVs-as-arrays (I assume=20
the () syntax is creating an array of some kind).<br></div></div></blockquo=
te><div><br>We still need a special "unpacking" syntax to bind the multi re=
turn values to variables because the comma operator is already taken and no=
t sufficient for this task. The following looks very confusing and it doesn=
't even account for multiple return values of different types. It also does=
n't let us assign return values directly to pre-existing variables.<br><br>=
<div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); b=
order-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; wo=
rd-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettypr=
int"><span style=3D"color: #660;" class=3D"styled-by-prettify">[</span><spa=
n style=3D"color: #008;" class=3D"styled-by-prettify">int</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color=
: #008;" class=3D"styled-by-prettify">int</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">,</span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">int</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">]</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> foo</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">();</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><=
/span><span style=3D"color: #008;" class=3D"styled-by-prettify">int</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"> bar</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">();</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color=
: #800;" class=3D"styled-by-prettify">//Initializes x, y, z using foo's ret=
urn values??</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"><br></span><span style=3D"color: #008;" class=3D"styled-by-prettify">int<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> x</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> y</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify"> z </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> foo</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">();</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"><br></span><span style=3D"color: #800;" class=3D"styled-by-prettify">//=
Initializes only c using bar's() return value and leaves a and b uninitiali=
zed</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></s=
pan><span style=3D"color: #008;" class=3D"styled-by-prettify">int</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> a</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> b</span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> c </span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> bar</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>();</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&n=
bsp;</span></div></code></div><br>We could allow using auto here:<br><div c=
lass=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); border-=
color: rgb(187, 187, 187); border-style: solid; border-width: 1px; word-wra=
p: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><=
span style=3D"color: #660;" class=3D"styled-by-prettify">[</span><span styl=
e=3D"color: #008;" class=3D"styled-by-prettify">int</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #008=
;" class=3D"styled-by-prettify">long</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">,</span><span style=3D"color: #008;" class=3D"sty=
led-by-prettify">double</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">]</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> foo</span><span style=3D"color: #660;" class=3D"styled-by-prettify">()=
;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></spa=
n><span style=3D"color: #008;" class=3D"styled-by-prettify">auto</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> x</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> y</span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> z </span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> foo</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>();</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </spa=
n><span style=3D"color: #800;" class=3D"styled-by-prettify">//x is int, y i=
s long, z is double</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"><br></span></div></code></div><br>But this still doesn't allow us =
to specify cv and ref qualifiers for the individual variables.<br>&nbsp;</d=
iv><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;=
border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><br><=
/div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;=
border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>&nbsp;</=
div><br><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8=
ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div><br><=
/div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;=
border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>As was s=
tated earlier, doing it this way would be a huge change that likely would n=
ever make it past the committee.</div></div></blockquote><div><br>But
 it's the right way to do it. And quite frankly, we don't need multiple=20
return values so badly that we should do it the wrong way just to have <i>s=
ome</i> convenient way to do it.<br><br>Some
 people use tuples a lot (some might say to the point of overuse). But=20
you shouldn't steal potentially useful syntax from those C++ programmers
 who don't use them. </div></div></blockquote><div><br></div><div>Programme=
rs
 who have no interest in tuple itself can just use the syntax to return=20
multiple values and unpack them at the call site. They don't have to=20
care that tuple (or something tuple like) is used to accomplish this.</div>=
</div></blockquote><div><br>Except that they have to pay the cost for it. C=
onsider something simple like this:<br><br><div style=3D"background-color:r=
gb(250,250,250);border-color:rgb(187,187,187);border-style:solid;border-wid=
th:1px;word-wrap:break-word"><code><div><span style=3D"color:#008">auto</sp=
an><span style=3D"color:#000"> single_value</span><span style=3D"color:#660=
">()</span><span style=3D"color:#000"><br></span><span style=3D"color:#660"=
>{</span><span style=3D"color:#000"><br>&nbsp; std</span><span style=3D"col=
or:#660">::</span><span style=3D"color:#008">string</span><span style=3D"co=
lor:#000"> a </span><span style=3D"color:#660">=3D</span><span style=3D"col=
or:#000"> </span><span style=3D"color:#660">...;</span><span style=3D"color=
:#000"><br>&nbsp; </span><span style=3D"color:#008">return</span><span styl=
e=3D"color:#000"> a</span><span style=3D"color:#660">;</span><span style=3D=
"color:#000"><br></span><span style=3D"color:#660">}</span><span style=3D"c=
olor:#000"><br><br></span><span style=3D"color:#008">auto</span><span style=
=3D"color:#000"> multi_value</span><span style=3D"color:#660">()</span><spa=
n style=3D"color:#000"><br></span><span style=3D"color:#660">{</span><span =
style=3D"color:#000"><br>&nbsp; std</span><span style=3D"color:#660">::</sp=
an><span style=3D"color:#008">string</span><span style=3D"color:#000"> a </=
span><span style=3D"color:#660">=3D</span><span style=3D"color:#000"> </spa=
n><span style=3D"color:#660">...;</span><span style=3D"color:#000"><br>&nbs=
p; std</span><span style=3D"color:#660">::</span><span style=3D"color:#000"=
>vector b </span><span style=3D"color:#660">=3D</span><span style=3D"color:=
#000"> </span><span style=3D"color:#660">...;</span><span style=3D"color:#0=
00"><br>&nbsp; </span><span style=3D"color:#008">return</span><span style=
=3D"color:#000"> </span><span style=3D"color:#660">[</span><span style=3D"c=
olor:#000">a</span><span style=3D"color:#660">;</span><span style=3D"color:=
#000"> b</span><span style=3D"color:#660">];</span><span style=3D"color:#00=
0"><br></span><span style=3D"color:#660">}</span></div></code></div><br>`si=
ngle_value`
 is subject to copy elision, so you should feel no problem with using=20
it. Even with a small-string-optimized std::string class, you will get=20
the maximum possible performance if you're using the result to=20
initialize an object.<br><br>With language-level multiple return values,
 `multi_value` would be able to operate under the same principle. `a`=20
and `b` would be considered return values, and they would each be=20
separately subject to elision.<br><br>With your way, that's just not=20
possible. If that syntax creates a `tuple`, then it must copy or move=20
initialize the elements of that `tuple`. So even though the `tuple`=20
itself is subject to elision, the creation of it is not.<br></div></div></b=
lockquote><div><br>So whats stopping someone from writing a proposal to all=
ow copy/move elision in your multi_value() example? Just because it can't h=
appen now doesn't mean we can't change the standard. Multi return values wo=
uld be a primary use case for such a proposal.<br><br></div><blockquote cla=
ss=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #=
ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><br></div><blockquote c=
lass=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #c=
cc solid;padding-left:1ex"><div dir=3D"ltr"><div>&nbsp;</div><blockquote cl=
ass=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #cc=
c solid;padding-left:1ex"><div dir=3D"ltr"><div>Syntax is a precious commod=
ity, which once apportioned, cannot be taken back.<br><br>It
 should also be noted that reflection, with the full ability to=20
compile-time inspect and generate types with full syntax=20
(including variable names) makes tuples... a dubious proposition for the
 future of C++. With reflection, you can index a struct by number. With=20
reflection, you can take any typelist and build an honest-to-God=20
struct out of it (which can be standard layout and such).<br><br>In=20
short, it is entirely possible that tuples will become obsolete, thus=20
also obsoleting this kind of syntax. So let's not have another std::bind
 happen here...<br></div></div></blockquote><div><br></div><div><div style=
=3D"border:1px solid rgb(187,187,187);word-wrap:break-word;background-color=
:rgb(250,250,250)"><code><div><span style=3D"color:#660">[</span><span styl=
e=3D"color:#008">int</span><span style=3D"color:#660">,</span><span style=
=3D"color:#008">long</span><span style=3D"color:#660">,</span><span style=
=3D"color:#008">double</span><span style=3D"color:#660">]</span><span style=
=3D"color:#000"> foo</span><span style=3D"color:#660">();</span><span style=
=3D"color:#000"><br></span><span style=3D"color:#008">auto</span><span styl=
e=3D"color:#000"> x </span><span style=3D"color:#660">=3D</span><span style=
=3D"color:#000"> foo</span><span style=3D"color:#660">();</span></div></cod=
e></div><br></div><div>Ok, if tuple is out then what is decltype(x) in the =
above example doing things your way?</div></div></blockquote><div><br>There=
 are two defensible answers to this:<br><br>1)
 A compilation error. You called a function that returns 3 things, but=20
you only captured one. That suggests you weren't paying attention.<br><br>2=
) `int`. The other two types are dropped on the floor.<br><br>#2 is probabl=
y the way to go. Any sort of aggregate object type is not even up for discu=
ssion.<br></div></div></blockquote><div><br>Then I should also ask you how =
do you plan on capturing the multiple values? Using a syntax similar to the=
 one I proposed?<br><br>This looks bad:<br><div class=3D"prettyprint" style=
=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187);=
 border-style: solid; border-width: 1px; word-wrap: break-word;"><code clas=
s=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #660;=
" class=3D"styled-by-prettify">[</span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">int</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">,</span><span style=3D"color: #008;" class=3D"styled-by-pr=
ettify">float</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">]</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> foo</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">();</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">[</span><span style=3D"co=
lor: #008;" class=3D"styled-by-prettify">auto</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"> x</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">auto</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> y</span><span style=3D"color: #660;" class=3D"styled-by-prettify">]</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> foo</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">();</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> </span><span style=3D"color: #800;" clas=
s=3D"styled-by-prettify">//Ok captures into x and y</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">[</span><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">auto</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> x</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">void</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">]</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> foo</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">();</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> </span><span style=3D"color: #800;" class=3D"st=
yled-by-prettify">//Ok captures first into x, throws away second</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span styl=
e=3D"color: #008;" class=3D"styled-by-prettify">auto</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> x </span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"> foo</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">();</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #800;" class=3D"styled-by-pr=
ettify">//Captures only first??</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"><br></span></div></code></div><br>The last line there =
looks like an easy recipe for bugs, especially in generic code. I would sug=
gest making it a compiler error.<br><br>Also what if I want to save the seq=
uence so that I can forward it multiple times?<br>Using your approach, I mi=
ght suggest allowing auto... to capture all of the return values so that th=
ey can be forwarded along. This could work just like a variadic template pa=
rameter pack.<br><br><div class=3D"prettyprint" style=3D"background-color: =
rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-style: solid; =
border-width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div=
 class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">void</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> foo</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</=
span><span style=3D"color: #008;" class=3D"styled-by-prettify">int</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #008;" class=3D"styled-by-prettify">float</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">[</span><span style=3D"color: #008;" class=3D"styled-by-=
prettify">int</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </spa=
n><span style=3D"color: #008;" class=3D"styled-by-prettify">float</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">]</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> bar</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">();</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"><br><br></span><span style=3D"color: #008=
;" class=3D"styled-by-prettify">auto</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">...</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> x </span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> bar</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(=
);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>foo<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify">x</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">...);</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br>foo</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify">x</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">...);</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"><br></span></div></code></div><br>But we still have the gen=
eric code problems that Miro brought up.<br>&nbsp;</div><blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;"><div dir=3D"ltr"><div><br>Multiple return value=
s means <i>multiple return values</i>, not "pack multiple values into some =
kind of object and unpack them later".<br>&nbsp;</div><blockquote class=3D"=
gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid=
;padding-left:1ex"><div dir=3D"ltr"><div>
 Another kind of typelist which is standard layout compatible? Or are we
 no longer able to capture all of the return values into one object?</div><=
/div></blockquote><div><br>If you want to capture them all in an object, yo=
u just ask for it:<br><br><div style=3D"background-color:rgb(250,250,250);b=
order-color:rgb(187,187,187);border-style:solid;border-width:1px;word-wrap:=
break-word"><code><div><span style=3D"color:#008">auto</span><span style=3D=
"color:#000"> x </span><span style=3D"color:#660">=3D</span><span style=3D"=
color:#000"> make_tuple</span><span style=3D"color:#660">(</span><span styl=
e=3D"color:#000">foo</span><span style=3D"color:#660">());</span></div></co=
de></div><br>That
 is neither hard nor particularly verbose. You can even stick them in an
 array, if all of the returned values are of the same type:<br><br><div sty=
le=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);borde=
r-style:solid;border-width:1px;word-wrap:break-word"><code><div><span style=
=3D"color:#008">auto</span><span style=3D"color:#000"> x </span><span style=
=3D"color:#660">=3D</span><span style=3D"color:#000"> make_array</span><spa=
n style=3D"color:#660">(</span><span style=3D"color:#000">foo</span><span s=
tyle=3D"color:#660">());</span></div></code></div><br></div></div></blockqu=
ote><div><br>These require copy/move. In your example, unpacking is free (n=
o-op) and packing requires a copy/move. In my example unpacking is free (us=
ing references) and packing is also free, assuming you want to continue usi=
ng the pack type returned by the function. <br></div><div>&nbsp;</div><bloc=
kquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-l=
eft: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div>Or in an arbi=
trary data structure:<br><br><div style=3D"background-color:rgb(250,250,250=
);border-color:rgb(187,187,187);border-style:solid;border-width:1px;word-wr=
ap:break-word"><code><div><span style=3D"color:#008">auto</span><span style=
=3D"color:#000"> x </span><span style=3D"color:#660">=3D</span><span style=
=3D"color:#000"> std</span><span style=3D"color:#660">::</span><span style=
=3D"color:#000">vector</span><span style=3D"color:#660">&lt;</span><span st=
yle=3D"color:#606">Type</span><span style=3D"color:#660">&gt;{</span><span =
style=3D"color:#000">foo</span><span style=3D"color:#660">()};</span><span =
style=3D"color:#000"><br></span></div></code></div><br>But
 most people using multiple return values don't capture them in a big=20
object, so we don't make the syntax optimal for that case.<br></div></div><=
/blockquote><div><br>Its not uncommon. Every class that has multiple "value=
s" (e.g unordered_map)&nbsp; will be returning them in a pack using its def=
ault iterators so that one can write a simple range for loop.<br>&nbsp;</di=
v><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;b=
order-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><br></=
div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;b=
order-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>If not us=
ing tuple, can you explain in a bit more detail how your proposed solution =
would actually work?</div></div></blockquote><div><br>The details of how it=
 works are more or less the way Lua works.<br><br>In C++ parlance, the noti=
on of a "sequence of values" would be a construct. It would <i>not</i>
 necessarily be an "expression", in the same way that a braced-init-list
 is not an expression. Since it's a new construct, you can give it=20
whatever properties you want.<br><br>Functions can return sequences of=20
values, with the sequence as a full part of its return type. Using the=20
sequence initialization syntax, you can initialize/assign multiple=20
variables to a sequence of values. If a sequence of values is given to a
 function argument list, the values are placed in that list as=20
arguments. If the sequence of values is used in any other kind of=20
expression, then it resolves down to the first element of that sequence=20
of values.<br><br>Initialization/assignment of variables through a sequence=
 would work element by element, in order from left to right.<br></div></div=
></blockquote><div><br>I would suggest maybe piggybacking off of varadic te=
mplate parameter packs (If they can fit into this feature) instead of inven=
ting a yet another brand new thing which is only used for multiple return v=
alues which itself does not show up very often.<br><br>You mentioned reflec=
tion before. I believe with reflection, we can achieve even better interfac=
es if we designed this MRV feature around unpacking collections of objects.=
<br>For example, imagine if we could unpack a pod struct like this (impleme=
nted using reflection):<br><br><div class=3D"prettyprint" style=3D"backgrou=
nd-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-styl=
e: solid; border-width: 1px; word-wrap: break-word;"><code class=3D"prettyp=
rint"><div class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"s=
tyled-by-prettify">struct</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> kv </span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
<br></span><span style=3D"color: #008;" class=3D"styled-by-prettify">string=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> key</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D=
"color: #008;" class=3D"styled-by-prettify">int</span><span style=3D"color:=
 #000;" class=3D"styled-by-prettify"> value</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">};</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"><br><br>kv kv</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"><br></span><span style=3D"color: #660;" class=3D"styled-by-prettify">[<=
/span><span style=3D"color: #008;" class=3D"styled-by-prettify">auto</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> k</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008=
;" class=3D"styled-by-prettify">auto</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> v</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">]</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> kv</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"><br></span></div></code=
></div><br>Why is this so great? Here is an example:<br><br><div class=3D"p=
rettyprint" style=3D"background-color: rgb(250, 250, 250); border-color: rg=
b(187, 187, 187); border-style: solid; border-width: 1px; word-wrap: break-=
word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span styl=
e=3D"color: #008;" class=3D"styled-by-prettify">template</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">&lt;</span><span style=3D"color: #008=
;" class=3D"styled-by-prettify">typename</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify"> K</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-pret=
tify">typename</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> V</span><span style=3D"color: #660;" class=3D"styled-by-prettify">&gt;=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span=
><span style=3D"color: #008;" class=3D"styled-by-prettify">class</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #606;" class=3D"styled-by-prettify">HashMap</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"><br></span><span style=3D"color: #008;" class=3D"=
styled-by-prettify">public</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">:</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"><br>&nbsp; </span><span style=3D"color: #008;" class=3D"styled-by-pr=
ettify">struct</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> kv </span><span style=3D"color: #660;" class=3D"styled-by-prettify">{<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> K key</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> V value</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">};</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>&nbsp; </span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">class</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> iterator </span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">:</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify=
">public</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> s=
td</span><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify">iterator</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">&lt;</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify">std</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify">bidirectional_iterator_tag</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify">kv</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">&gt;</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> </span><span style=3D"color: #800;" class=3D"styled-by-prettify=
">/* ... */</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">};</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; </spa=
n><span style=3D"color: #800;" class=3D"styled-by-prettify">//...</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">};</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"><br><br></span><span style=3D"colo=
r: #606;" class=3D"styled-by-prettify">HashMap</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> hashmap </span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"> </span><span style=3D"color: #800;" class=3D"s=
tyled-by-prettify">/* something */</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br><br></span><span style=3D"color: #800;" class=3D"styled-=
by-prettify">//Iterate using kv struct (more descriptive than pair)</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span s=
tyle=3D"color: #008;" class=3D"styled-by-prettify">for</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #=
008;" class=3D"styled-by-prettify">auto</span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">&amp;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> kv</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">:</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> hashmap</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">)</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; doSomethin=
g</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify">kv</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">.</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify">key</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> kv</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">.</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify">value</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">}</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br><br></span><span=
 style=3D"color: #800;" class=3D"styled-by-prettify">//Iterate by unpacking=
 the kv struct first</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"><br></span><span style=3D"color: #008;" class=3D"styled-by-pretti=
fy">for</span><span style=3D"color: #660;" class=3D"styled-by-prettify">([<=
/span><span style=3D"color: #008;" class=3D"styled-by-prettify">auto</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">&amp;</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify"> key</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" =
class=3D"styled-by-prettify">auto</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">&amp;</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> value</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">]:</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> hashmap</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">)</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbsp; doSomething=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify">key</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> value</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">}</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br><br></span><span style=3D"color: #800;" class=3D"styled-=
by-prettify">//Iterate over only the keys</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"><br></span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">for</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">([</span><span style=3D"color: #008;" class=3D"styled-by-=
prettify">auto</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">&amp;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
key</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span st=
yle=3D"color: #008;" class=3D"styled-by-prettify">void</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">]:</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> hashmap</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">)</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">{}</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"><br><br></span><span style=3D"color: #800;" class=3D"styled-by-pret=
tify">//Iterate over only the values</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"><br></span><span style=3D"color: #008;" class=3D"=
styled-by-prettify">for</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">([</span><span style=3D"color: #008;" class=3D"styled-by-prett=
ify">void</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><s=
pan style=3D"color: #008;" class=3D"styled-by-prettify">auto</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">&amp;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> value</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">]:</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"> hashmap</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">{}</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"><br></span></div></code></div><br>If the MRV feature is designed aro=
und unpacking collections of objects, then we can get interfaces like this =
for free from reflection. All 4 example loops are enabled without any addit=
ional work by the author of HashMap. <br><br>If MRV is designed using seque=
nces, then the class author has to provide separate iterators for returning=
 an MRV sequence and also returning a pack in the default iterators. Class =
designers are already overburdened with boilerplate for writing type trait =
tags, iterator types, copy/move constructors, comparison operators, swap op=
erator, etc.. <br></div><br>The Lua way of doing things might be elegant, b=
ut lua is also a very simple language. It doesn't have the same features an=
d restrictions of C++ and I'm not sure yet if that approach would be the be=
st way.<br><br>On Wednesday, May 27, 2015 at 4:51:58 AM UTC-4, Miro Knejp w=
rote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8e=
x;border-left: 1px #ccc solid;padding-left: 1ex;"><div style=3D"word-wrap:b=
reak-word">I assume Matthew=E2=80=99s point comes from dealing with templat=
e code.<div><br></div><div>template&lt;class F&gt;</div><div>??? contrived_=
example(F f) {</div><div>&nbsp; &nbsp; return f();</div><div>}</div><div><b=
r></div><div>The author would probably expect that ??? can be plain =E2=80=
=9Cauto=E2=80=9D, implying =E2=80=9Cin some places auto can expand to multi=
ple types=E2=80=9D. Then there=E2=80=99s the point of what generic code wou=
ld require to do to consistently capture the return value(s) of a Callable =
without knowing if there are one or multiple return values.</div><div><br><=
/div><div>template&lt;class F&gt;</div><div>void contrived_example2(F f) {<=
/div><div>&nbsp; &nbsp; ??? x =3D f();</div><div>&nbsp; &nbsp; ...</div><di=
v>}</div><div><br></div><div>Should ??? be something that can potentially c=
apture a single or multiple values depending on the initialization? If so w=
hat can be done with x down the pipeline? Or is a concept necessary to over=
load contrived_example2 for functions with single or multiple return values=
? Is template code forced into packing every Callable=E2=80=99s invocation =
into make_tuple() just in case it might return multiple values?</div><div><=
br></div></div></blockquote><div><br>These are very good questions. If mult=
i return is just sugar for returning a pack type, then generic code works j=
ust fine without any issue. If not, then we have a lot of questions to answ=
er. <br></div></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_174_1468761672.1432739494049--
------=_Part_173_2103744840.1432739494049--

.
