Topic: [Ranges] n4560: tagged_tuple and unnamed structs
Author: "Vicente J. Botet Escriba" <vicente.botet@wanadoo.fr>
Date: Wed, 30 Dec 2015 17:37:35 +0100
Raw View
This is a multi-part message in MIME format.
--------------000408070409000206050900
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: quoted-printable
Le 30/12/2015 15:24, Giovanni Piero Deretta a =C3=A9crit :
> On Wednesday, December 30, 2015 at 1:20:35 PM UTC, Vicente J. Botet=20
> Escriba wrote:
>
> [...]
> I'm getting a compile error while trying to return an unnamed
> struct from a function (I don't know where in the standard this
> limitation appears)
>
> struct { // ERROR
> int first;
> int second;
> }
> a_pair()
> {
> return {1, -1};
> }
>
> error: '(anonymous struct at pair_pass.cpp:91:7)' cannot be
> defined in the result type of a function
> struct {
>
> [...]
> Is there any reason to don't support functions/lambdas returning
> unnamed structs?
>
>
> This works in C++14:
>
> auto a_pair ()
> {
> struct { int first; int second; } r {0, 1};
> return r;
> }
>
> Is this similar to what you had in mind?
Hmm, yes and not. This works if the function body is in the declaration.=20
However, it is not practical to define an interface in the standard :(
Vicente
--=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 https://groups.google.com/a/isocpp.org/group/std-propos=
als/.
--------------000408070409000206050900
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta content=3D"text/html; charset=3Dwindows-1252"
http-equiv=3D"Content-Type">
</head>
<body bgcolor=3D"#FFFFFF" text=3D"#000000">
<div class=3D"moz-cite-prefix">Le 30/12/2015 15:24, Giovanni Piero
Deretta a =C3=A9crit=C2=A0:<br>
</div>
<blockquote
cite=3D"mid:8b2a4a26-ea3c-4848-a5a0-869d794a343f@isocpp.org"
type=3D"cite">On Wednesday, December 30, 2015 at 1:20:35 PM UTC,
Vicente J. Botet Escriba wrote:
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<div bgcolor=3D"#FFFFFF" text=3D"#000000"> [...]<br>
I'm getting a compile error while trying to return an unnamed
struct from a function (I don't know where in the standard
this limitation appears)<br>
<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 struct {=C2=A0=C2=A0 // ERROR<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int first;=
<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int second=
;<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 a_pair()<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 {<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return {1, -1};<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }<br>
<br>
error: '(anonymous struct at pair_pass.cpp:91:7)' cannot be
defined in the result type of a function<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 struct {<br>
<br>
[...]<br>
Is there any reason to don't support functions/lambdas
returning unnamed structs?<br>
</div>
</blockquote>
<div><br>
This works in C++14:<br>
<br>
auto a_pair ()<br>
{<br>
=C2=A0=C2=A0 struct { int first; int second; } r {0, 1};<br>
=C2=A0=C2=A0 return r;<br>
}<br>
<br>
Is this similar to what you had in mind?<br>
</div>
</blockquote>
Hmm, yes and not. This works if the function body is in the
declaration. However, it is not practical to define an interface in
the standard :(<br>
<br>
Vicente<br>
</body>
</html>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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"https://groups.google.com/a/isocpp.org/group=
/std-proposals/">https://groups.google.com/a/isocpp.org/group/std-proposals=
/</a>.<br />
--------------000408070409000206050900--
.
Author: Matthew Woehlke <mwoehlke.floss@gmail.com>
Date: Wed, 30 Dec 2015 12:04:04 -0500
Raw View
On 2015-12-30 11:37, Vicente J. Botet Escriba wrote:
> Le 30/12/2015 15:24, Giovanni Piero Deretta a =C3=A9crit :
>> This works in C++14:
>>
>> auto a_pair ()
>> {
>> struct { int first; int second; } r {0, 1};
>> return r;
>> }
>>
>> Is this similar to what you had in mind?
>
> Hmm, yes and not. This works if the function body is in the declaration.
> However, it is not practical to define an interface in the standard :(
Functions cannot be overloaded by return value. That being the case, is
there a reason why this "shouldn't" work?
// foo.h
struct { int first; double second; } foo(...);
// foo.cpp
auto foo(...)
{
...
return { 1, 5.25 };
}
By "shouldn't", I don't mean according to the current standard (or maybe
it "should" in that sense already?), but rather as a possible proposal.
More generally, would it be reasonable for a definition having a return
value of 'auto' with no trailing return specification, for which a
declaration has been previously seen that had a concrete return type, to
"inherit" the previously seen return type?
(And, yes, in theory right now one can use decltype with a "fake" call
to the function, i.e. 'decltype(foo(...))', but this requires supplying
arguments, which is verbose and can be awkward.)
--=20
Matthew
--=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 https://groups.google.com/a/isocpp.org/group/std-propos=
als/.
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Wed, 30 Dec 2015 10:18:10 -0800 (PST)
Raw View
------=_Part_1260_639251290.1451499490681
Content-Type: multipart/alternative;
boundary="----=_Part_1261_84698997.1451499490682"
------=_Part_1261_84698997.1451499490682
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Wednesday, December 30, 2015 at 12:04:14 PM UTC-5, Matthew Woehlke wrote=
:
>
> On 2015-12-30 11:37, Vicente J. Botet Escriba wrote:=20
> > Le 30/12/2015 15:24, Giovanni Piero Deretta a =C3=A9crit :=20
> >> This works in C++14:=20
> >>=20
> >> auto a_pair ()=20
> >> {=20
> >> struct { int first; int second; } r {0, 1};=20
> >> return r;=20
> >> }=20
> >>=20
> >> Is this similar to what you had in mind?=20
> >=20
> > Hmm, yes and not. This works if the function body is in the declaration=
..=20
> > However, it is not practical to define an interface in the standard :(=
=20
>
> Functions cannot be overloaded by return value. That being the case, is=
=20
> there a reason why this "shouldn't" work?=20
>
> // foo.h=20
> struct { int first; double second; } foo(...);=20
>
> // foo.cpp=20
> auto foo(...)=20
> {=20
> ...=20
> return { 1, 5.25 };=20
> }=20
>
> By "shouldn't", I don't mean according to the current standard (or maybe=
=20
> it "should" in that sense already?), but rather as a possible proposal.
>
=20
>
More generally, would it be reasonable for a definition having a return=20
> value of 'auto' with no trailing return specification, for which a=20
> declaration has been previously seen that had a concrete return type, to=
=20
> "inherit" the previously seen return type?=20
>
.... Of course it should. That's like the best idea anyone has had all year.=
=20
Including mine.
--=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 https://groups.google.com/a/isocpp.org/group/std-propos=
als/.
------=_Part_1261_84698997.1451499490682
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<br><br>On Wednesday, December 30, 2015 at 12:04:14 PM UTC-5, Matthew Woehl=
ke wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: =
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On 2015-12-30 11:37, =
Vicente J. Botet Escriba wrote:
<br>> Le 30/12/2015 15:24, Giovanni Piero Deretta a =C3=A9crit :
<br>>> This works in C++14:
<br>>>
<br>>> auto a_pair ()
<br>>> {
<br>>> =C2=A0 =C2=A0struct { int first; int second; } r {0, 1};
<br>>> =C2=A0 =C2=A0return r;
<br>>> }
<br>>>
<br>>> Is this similar to what you had in mind?
<br>>
<br>> Hmm, yes and not. This works if the function body is in the declar=
ation.
<br>> However, it is not practical to define an interface in the standar=
d :(
<br>
<br>Functions cannot be overloaded by return value. That being the case, is
<br>there a reason why this "shouldn't" work?
<br>
<br>=C2=A0 // foo.h
<br>=C2=A0 struct { int first; double second; } foo(...);
<br>
<br>=C2=A0 // foo.cpp
<br>=C2=A0 auto foo(...)
<br>=C2=A0 {
<br>=C2=A0 =C2=A0 ...
<br>=C2=A0 =C2=A0 return { 1, 5.25 };
<br>=C2=A0 }
<br>
<br>By "shouldn't", I don't mean according to the current=
standard (or maybe
<br>it "should" in that sense already?), but rather as a possible=
proposal.<br></blockquote><blockquote style=3D"margin: 0px 0px 0px 0.8ex; =
border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;" class=3D"gma=
il_quote"><div>=C2=A0</div></blockquote><blockquote class=3D"gmail_quote" s=
tyle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-le=
ft: 1ex;">More generally, would it be reasonable for a definition having a =
return
<br>value of 'auto' with no trailing return specification, for whic=
h a
<br>declaration has been previously seen that had a concrete return type, t=
o
<br>"inherit" the previously seen return type?
<br></blockquote><div><br>... Of course it should. That's like the best=
idea anyone has had all year. Including mine.</div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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"https://groups.google.com/a/isocpp.org/group=
/std-proposals/">https://groups.google.com/a/isocpp.org/group/std-proposals=
/</a>.<br />
------=_Part_1261_84698997.1451499490682--
------=_Part_1260_639251290.1451499490681--
.
Author: Casey Carter <Casey@Carter.net>
Date: Wed, 30 Dec 2015 13:18:08 -0600
Raw View
--089e01538e5e00ab6405282266c0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Wed, Dec 30, 2015 at 7:20 AM, Vicente J. Botet Escriba <
vicente.botet@wanadoo.fr> wrote:
> Hi,
>
> n4560 introduce the classes tagged, tagged_pair and tagged_tuple. Here
> follows the rationale as described in n4560:
>
> *[Editor=E2=80=99s note: This type exists so that the algorithms can retu=
rn pair-
> and tuple-like objects with named accessors, as requested by LEWG. Rather
> than create a bunch of one-off class types with no relation to pair and
> tuple, I opted instead to create a general utility. I=E2=80=99ll note tha=
t this
> functionality can be merged into pair and tuple directly with minimal
> breakage, but I opted for now to keep it separate.]*
>
>
> I was wondering if
>
> tagged_pair<tag::in(I), tag::fun(Fun)>
>
> couldn't be better be represented by the unnamed aggregate
>
> struct {
> I in;
> Fun fun;
> }
>
> which has less noise.
>
Much of the motivation for tagged is to maintain a reasonable level of
backwards compatibility for algorithms that return pairs/tuples in C++14.
Since tagged_foo publicly inherits from foo, a tagged_pair is-a std::pair.
C++14 code that wants to e.g. use mismatch(...).first or assign the result
of mismatch to a std::pair of iterators continues to be valid under the
Ranges TS. That would not be the case if mismatch returns a type that
doesn't have members named first and second or is not convertible to
std::pair.
--=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 https://groups.google.com/a/isocpp.org/group/std-propos=
als/.
--089e01538e5e00ab6405282266c0
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">On W=
ed, Dec 30, 2015 at 7:20 AM, Vicente J. Botet Escriba <span dir=3D"ltr"><=
;<a href=3D"mailto:vicente.botet@wanadoo.fr" target=3D"_blank">vicente.bote=
t@wanadoo.fr</a>></span> wrote:<br><blockquote class=3D"gmail_quote" sty=
le=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
=20
=20
=20
<div bgcolor=3D"#FFFFFF" text=3D"#000000">
Hi,<br>
<br>
n4560 introduce the classes tagged, tagged_pair and tagged_tuple.
Here follows the rationale as described in n4560:<br>
=20
<br>
<i>[Editor=E2=80=99s note: This type exists so that the algorithms can
return pair- and tuple-like objects with named
accessors, as requested by LEWG. Rather than create a bunch of
one-off class types with no relation to pair
and tuple, I opted instead to create a general utility. I=E2=80=99ll =
note
that this functionality can be merged into
pair and tuple directly with minimal breakage, but I opted for now
to keep it separate.]</i><i><br>
</i><br>
<br>
I was wondering if<br>
<br>
=C2=A0=C2=A0=C2=A0 tagged_pair<tag::in(I), tag::fun(Fun)><br>
<br>
couldn't be better be represented by the unnamed aggregate<br>
<br>
=C2=A0=C2=A0=C2=A0 struct {<br>
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 I in;<br>
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 Fun fun;<br>
=C2=A0=C2=A0=C2=A0 }<br>
<br>
which has less noise.<br></div></blockquote><div><br></div><div>Much of=
the motivation for <font face=3D"monospace, monospace">tagged</font> is to=
maintain a reasonable level of backwards compatibility for algorithms that=
return pairs/tuples in C++14. Since <font face=3D"monospace, monospace">ta=
gged_foo</font> publicly inherits from <font face=3D"monospace, monospace">=
foo</font>, a <font face=3D"monospace, monospace">tagged_pair</font> is-a <=
font face=3D"monospace, monospace">std::pair</font>. C++14 code that wants =
to e.g. use <font face=3D"monospace, monospace">mismatch(...).first</font> =
or assign the result of <font face=3D"monospace, monospace">mismatch </font=
>to a <font face=3D"monospace, monospace">std::pair</font> of iterators con=
tinues to be valid under the Ranges TS. That would not be the case if <font=
face=3D"monospace, monospace">mismatch </font>returns a type that doesn=
9;t have members named <font face=3D"monospace, monospace">first </font>and=
<font face=3D"monospace, monospace">second </font>or is not convertible to=
<font face=3D"monospace, monospace">std::pair</font>.</div></div>
</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" 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"https://groups.google.com/a/isocpp.org/group=
/std-proposals/">https://groups.google.com/a/isocpp.org/group/std-proposals=
/</a>.<br />
--089e01538e5e00ab6405282266c0--
.
Author: "Vicente J. Botet Escriba" <vicente.botet@wanadoo.fr>
Date: Wed, 30 Dec 2015 21:02:03 +0100
Raw View
This is a multi-part message in MIME format.
--------------040706060403040307090008
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: quoted-printable
Le 30/12/2015 20:18, Casey Carter a =C3=A9crit :
> On Wed, Dec 30, 2015 at 7:20 AM, Vicente J. Botet Escriba=20
> <vicente.botet@wanadoo.fr <mailto:vicente.botet@wanadoo.fr>> wrote:
>
> Hi,
>
> n4560 introduce the classes tagged, tagged_pair and tagged_tuple.
> Here follows the rationale as described in n4560:
>
> /[Editor=E2=80=99s note: This type exists so that the algorithms can
> return pair- and tuple-like objects with named accessors, as
> requested by LEWG. Rather than create a bunch of one-off class
> types with no relation to pair and tuple, I opted instead to
> create a general utility. I=E2=80=99ll note that this functionality c=
an be
> merged into pair and tuple directly with minimal breakage, but I
> opted for now to keep it separate.]//
> /
>
> I was wondering if
>
> tagged_pair<tag::in(I), tag::fun(Fun)>
>
> couldn't be better be represented by the unnamed aggregate
>
> struct {
> I in;
> Fun fun;
> }
>
> which has less noise.
>
>
> Much of the motivation for tagged is to maintain a reasonable level of=20
> backwards compatibility for algorithms that return pairs/tuples in=20
> C++14. Since tagged_foo publicly inherits from foo, a tagged_pair is-a=20
> std::pair. C++14 code that wants to e.g. use mismatch(...).first or=20
> assign the result of mismatch to a std::pair of iterators continues to=20
> be valid under the Ranges TS. That would not be the case if mismatch=20
> returns a type that doesn't have members named first and second or is=20
> not convertible to std::pair.
>
Thanks for the describing more clearly the motivation.
It is too bad we need to be as backward compatible as possible.
Vicente
--=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 https://groups.google.com/a/isocpp.org/group/std-propos=
als/.
--------------040706060403040307090008
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta content=3D"text/html; charset=3Dutf-8" http-equiv=3D"Content-Type=
">
</head>
<body bgcolor=3D"#FFFFFF" text=3D"#000000">
<div class=3D"moz-cite-prefix">Le 30/12/2015 20:18, Casey Carter a
=C3=A9crit=C2=A0:<br>
</div>
<blockquote
cite=3D"mid:CAJw-yXn1AWv7OjxRqiro4jRpULGyPttospSPETD1_rRRFcshtg@mail.gmail.=
com"
type=3D"cite">
<div dir=3D"ltr">
<div class=3D"gmail_extra">
<div class=3D"gmail_quote">On Wed, Dec 30, 2015 at 7:20 AM,
Vicente J. Botet Escriba <span dir=3D"ltr"><<a
moz-do-not-send=3D"true"
href=3D"mailto:vicente.botet@wanadoo.fr" target=3D"_blank">=
<a class=3D"moz-txt-link-abbreviated" href=3D"mailto:vicente.botet@wanadoo.=
fr">vicente.botet@wanadoo.fr</a></a>></span>
wrote:<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0
.8ex;border-left:1px #ccc solid;padding-left:1ex">
<div bgcolor=3D"#FFFFFF" text=3D"#000000"> Hi,<br>
<br>
n4560 introduce the classes tagged, tagged_pair and
tagged_tuple. Here follows the rationale as described in
n4560:<br>
<br>
<i>[Editor=E2=80=99s note: This type exists so that the
algorithms can return pair- and tuple-like objects
with named accessors, as requested by LEWG. Rather
than create a bunch of one-off class types with no
relation to pair and tuple, I opted instead to create
a general utility. I=E2=80=99ll note that this functional=
ity
can be merged into pair and tuple directly with
minimal breakage, but I opted for now to keep it
separate.]</i><i><br>
</i><br>
<br>
I was wondering if<br>
<br>
=C2=A0=C2=A0=C2=A0 tagged_pair<tag::in(I), tag::fun(Fun)=
><br>
<br>
couldn't be better be represented by the unnamed
aggregate<br>
<br>
=C2=A0=C2=A0=C2=A0 struct {<br>
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 I in;<br>
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 Fun fun;<br>
=C2=A0=C2=A0=C2=A0 }<br>
<br>
which has less noise.<br>
</div>
</blockquote>
<div><br>
</div>
<div>Much of the motivation for <font face=3D"monospace,
monospace">tagged</font> is to maintain a reasonable
level of backwards compatibility for algorithms that
return pairs/tuples in C++14. Since <font
face=3D"monospace, monospace">tagged_foo</font> publicly
inherits from <font face=3D"monospace, monospace">foo</font>,
a <font face=3D"monospace, monospace">tagged_pair</font>
is-a <font face=3D"monospace, monospace">std::pair</font>.
C++14 code that wants to e.g. use <font face=3D"monospace,
monospace">mismatch(...).first</font> or assign the
result of <font face=3D"monospace, monospace">mismatch </font=
>to
a <font face=3D"monospace, monospace">std::pair</font> of
iterators continues to be valid under the Ranges TS. That
would not be the case if <font face=3D"monospace,
monospace">mismatch </font>returns a type that doesn't
have members named <font face=3D"monospace, monospace">first
</font>and <font face=3D"monospace, monospace">second </font>=
or
is not convertible to <font face=3D"monospace, monospace">std=
::pair</font>.</div>
</div>
</div>
</div>
<br>
</blockquote>
Thanks for the describing more clearly the motivation.<br>
<br>
It is too bad we need to be as backward compatible as possible.<br>
<br>
Vicente<br>
</body>
</html>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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"https://groups.google.com/a/isocpp.org/group=
/std-proposals/">https://groups.google.com/a/isocpp.org/group/std-proposals=
/</a>.<br />
--------------040706060403040307090008--
.
Author: "Vicente J. Botet Escriba" <vicente.botet@wanadoo.fr>
Date: Wed, 30 Dec 2015 21:15:16 +0100
Raw View
This is a multi-part message in MIME format.
--------------090602090808060303090601
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: quoted-printable
Le 30/12/2015 19:18, Nicol Bolas a =C3=A9crit :
>
>
> On Wednesday, December 30, 2015 at 12:04:14 PM UTC-5, Matthew Woehlke=20
> wrote:
>
> On 2015-12-30 11:37, Vicente J. Botet Escriba wrote:
> > Le 30/12/2015 15:24, Giovanni Piero Deretta a =C3=A9crit :
> >> This works in C++14:
> >>
> >> auto a_pair ()
> >> {
> >> struct { int first; int second; } r {0, 1};
> >> return r;
> >> }
> >>
> >> Is this similar to what you had in mind?
> >
> > Hmm, yes and not. This works if the function body is in the
> declaration.
> > However, it is not practical to define an interface in the
> standard :(
>
> Functions cannot be overloaded by return value. That being the
> case, is
> there a reason why this "shouldn't" work?
>
> // foo.h
> struct { int first; double second; } foo(...);
>
> // foo.cpp
> auto foo(...)
> {
> ...
> return { 1, 5.25 };
> }
>
> By "shouldn't", I don't mean according to the current standard (or
> maybe
> it "should" in that sense already?), but rather as a possible
> proposal.
>
> More generally, would it be reasonable for a definition having a
> return
> value of 'auto' with no trailing return specification, for which a
> declaration has been previously seen that had a concrete return
> type, to
> "inherit" the previously seen return type?
>
>
> ... Of course it should. That's like the best idea anyone has had all=20
> year. Including mine.
>
I find it interesting also. This feature is independent of returning=20
unnamed structs and merits a separated proposal.
Vicente
--=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 https://groups.google.com/a/isocpp.org/group/std-propos=
als/.
--------------090602090808060303090601
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta content=3D"text/html; charset=3Dutf-8" http-equiv=3D"Content-Type=
">
</head>
<body bgcolor=3D"#FFFFFF" text=3D"#000000">
<div class=3D"moz-cite-prefix">Le 30/12/2015 19:18, Nicol Bolas a
=C3=A9crit=C2=A0:<br>
</div>
<blockquote
cite=3D"mid:8aa6d4ca-7235-4d37-afe6-8cbe10b37b38@isocpp.org"
type=3D"cite"><br>
<br>
On Wednesday, December 30, 2015 at 12:04:14 PM UTC-5, Matthew
Woehlke wrote:
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On
2015-12-30 11:37, Vicente J. Botet Escriba wrote:
<br>
> Le 30/12/2015 15:24, Giovanni Piero Deretta a =C3=A9crit :
<br>
>> This works in C++14:
<br>
>>
<br>
>> auto a_pair ()
<br>
>> {
<br>
>> =C2=A0 =C2=A0struct { int first; int second; } r {0, 1};
<br>
>> =C2=A0 =C2=A0return r;
<br>
>> }
<br>
>>
<br>
>> Is this similar to what you had in mind?
<br>
>
<br>
> Hmm, yes and not. This works if the function body is in the
declaration.
<br>
> However, it is not practical to define an interface in the
standard :(
<br>
<br>
Functions cannot be overloaded by return value. That being the
case, is
<br>
there a reason why this "shouldn't" work?
<br>
<br>
=C2=A0 // foo.h
<br>
=C2=A0 struct { int first; double second; } foo(...);
<br>
<br>
=C2=A0 // foo.cpp
<br>
=C2=A0 auto foo(...)
<br>
=C2=A0 {
<br>
=C2=A0 =C2=A0 ...
<br>
=C2=A0 =C2=A0 return { 1, 5.25 };
<br>
=C2=A0 }
<br>
<br>
By "shouldn't", I don't mean according to the current standard
(or maybe
<br>
it "should" in that sense already?), but rather as a possible
proposal.<br>
</blockquote>
<blockquote style=3D"margin: 0px 0px 0px 0.8ex; border-left: 1px
solid rgb(204, 204, 204); padding-left: 1ex;"
class=3D"gmail_quote">
<div>=C2=A0</div>
</blockquote>
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">More
generally, would it be reasonable for a definition having a
return
<br>
value of 'auto' with no trailing return specification, for which
a
<br>
declaration has been previously seen that had a concrete return
type, to
<br>
"inherit" the previously seen return type?
<br>
</blockquote>
<div><br>
... Of course it should. That's like the best idea anyone has
had all year. Including mine.</div>
<br>
</blockquote>
I find it interesting also. This feature is independent of returning
unnamed structs and merits a separated proposal.<br>
<br>
Vicente<br>
</body>
</html>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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"https://groups.google.com/a/isocpp.org/group=
/std-proposals/">https://groups.google.com/a/isocpp.org/group/std-proposals=
/</a>.<br />
--------------090602090808060303090601--
.
Author: Giovanni Piero Deretta <gpderetta@gmail.com>
Date: Wed, 30 Dec 2015 23:52:51 -0800 (PST)
Raw View
------=_Part_4942_37920223.1451548371209
Content-Type: multipart/alternative;
boundary="----=_Part_4943_1027617771.1451548371209"
------=_Part_4943_1027617771.1451548371209
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Wednesday, December 30, 2015 at 4:37:39 PM UTC, Vicente J. Botet Escriba=
=20
wrote:
>
> Le 30/12/2015 15:24, Giovanni Piero Deretta a =C3=A9crit :
>
> On Wednesday, December 30, 2015 at 1:20:35 PM UTC, Vicente J. Botet=20
> Escriba wrote:=20
>>
>> [...]
>> I'm getting a compile error while trying to return an unnamed struct fro=
m=20
>> a function (I don't know where in the standard this limitation appears)
>>
>> struct { // ERROR
>> int first;
>> int second;
>> }
>> a_pair()
>> {
>> return {1, -1};
>> }
>>
>> error: '(anonymous struct at pair_pass.cpp:91:7)' cannot be defined in=
=20
>> the result type of a function
>> struct {
>>
>> [...]
>> Is there any reason to don't support functions/lambdas returning unnamed=
=20
>> structs?
>>
>
> This works in C++14:
>
> auto a_pair ()
> {
> struct { int first; int second; } r {0, 1};
> return r;
> }
>
> Is this similar to what you had in mind?
>
> Hmm, yes and not. This works if the function body is in the declaration.=
=20
> However, it is not practical to define an interface in the standard :(
>
>
hum, what's the problem exactly? As far as I understand, the use case is=20
range algorithms, i.e. template functions which are in practice always=20
defined inline. The standard spec would simply say that these algorithms=
=20
return an unspecified type which has certain properties.
-- gpd
=20
> Vicente
>
--=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 https://groups.google.com/a/isocpp.org/group/std-propos=
als/.
------=_Part_4943_1027617771.1451548371209
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Wednesday, December 30, 2015 at 4:37:39 PM UTC, Vicente J. Botet Escriba=
wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.=
8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
=20
=20
=20
<div bgcolor=3D"#FFFFFF" text=3D"#000000">
<div>Le 30/12/2015 15:24, Giovanni Piero
Deretta a =C3=A9crit=C2=A0:<br>
</div>
<blockquote type=3D"cite">On Wednesday, December 30, 2015 at 1:20:35 PM=
UTC,
Vicente J. Botet Escriba wrote:
<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex=
;border-left:1px #ccc solid;padding-left:1ex">
<div bgcolor=3D"#FFFFFF" text=3D"#000000"> [...]<br>
I'm getting a compile error while trying to return an unnamed
struct from a function (I don't know where in the standard
this limitation appears)<br>
<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 struct {=C2=A0=C2=A0 // ERROR<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int first;=
<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int second=
;<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 a_pair()<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 {<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return {1, -1};<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }<br>
<br>
error: '(anonymous struct at pair_pass.cpp:91:7)' cannot =
be
defined in the result type of a function<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 struct {<br>
<br>
[...]<br>
Is there any reason to don't support functions/lambdas
returning unnamed structs?<br>
</div>
</blockquote>
<div><br>
This works in C++14:<br>
<br>
auto a_pair ()<br>
{<br>
=C2=A0=C2=A0 struct { int first; int second; } r {0, 1};<br>
=C2=A0=C2=A0 return r;<br>
}<br>
<br>
Is this similar to what you had in mind?<br>
</div>
</blockquote>
Hmm, yes and not. This works if the function body is in the
declaration. However, it is not practical to define an interface in
the standard :(<br>
<br></div></blockquote><div><br>hum, what's the problem exactly? As=
far as I understand, the use case is range algorithms, i.e. template funct=
ions which are in practice always defined inline.=C2=A0 The standard spec w=
ould simply say that these algorithms return an unspecified type which has =
certain properties.<br><br>-- gpd<br>=C2=A0</div><blockquote class=3D"gmail=
_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;p=
adding-left: 1ex;"><div bgcolor=3D"#FFFFFF" text=3D"#000000">
Vicente<br>
</div>
</blockquote>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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"https://groups.google.com/a/isocpp.org/group=
/std-proposals/">https://groups.google.com/a/isocpp.org/group/std-proposals=
/</a>.<br />
------=_Part_4943_1027617771.1451548371209--
------=_Part_4942_37920223.1451548371209--
.
Author: "Vicente J. Botet Escriba" <vicente.botet@wanadoo.fr>
Date: Thu, 31 Dec 2015 12:44:54 +0100
Raw View
This is a multi-part message in MIME format.
--------------050607000500030401010608
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: quoted-printable
Le 31/12/2015 08:52, Giovanni Piero Deretta a =C3=A9crit :
> On Wednesday, December 30, 2015 at 4:37:39 PM UTC, Vicente J. Botet=20
> Escriba wrote:
>
> Le 30/12/2015 15:24, Giovanni Piero Deretta a =C3=A9crit :
>> On Wednesday, December 30, 2015 at 1:20:35 PM UTC, Vicente J.
>> Botet Escriba wrote:
>>
>> [...]
>> I'm getting a compile error while trying to return an unnamed
>> struct from a function (I don't know where in the standard
>> this limitation appears)
>>
>> struct { // ERROR
>> int first;
>> int second;
>> }
>> a_pair()
>> {
>> return {1, -1};
>> }
>>
>> error: '(anonymous struct at pair_pass.cpp:91:7)' cannot be
>> defined in the result type of a function
>> struct {
>>
>> [...]
>> Is there any reason to don't support functions/lambdas
>> returning unnamed structs?
>>
>>
>> This works in C++14:
>>
>> auto a_pair ()
>> {
>> struct { int first; int second; } r {0, 1};
>> return r;
>> }
>>
>> Is this similar to what you had in mind?
> Hmm, yes and not. This works if the function body is in the
> declaration. However, it is not practical to define an interface
> in the standard :(
>
>
> hum, what's the problem exactly? As far as I understand, the use case=20
> is range algorithms, i.e. template functions which are in practice=20
> always defined inline. The standard spec would simply say that these=20
> algorithms return an unspecified type which has certain properties.
>
You are right for this specific use case. However I suspect that the=20
wording sating that the user just can access the parts and can do=20
nothing with the global result will be not enough.
As Tony as signaled, unnamed structs are different types on the same=20
translation unit.
Given
|
struct{inti;}a,foo();
struct{inti;}bar();
|
can you write `a =3D bar();`?
Something must be changed to consider unnamed structs (or something=20
else) to have the same type if the parts are the same.
If this issue is solved and if IRTVPDUA proposal was adopted, the=20
interface could even use the unnamed struct.
Vicente
--=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 https://groups.google.com/a/isocpp.org/group/std-propos=
als/.
--------------050607000500030401010608
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta content=3D"text/html; charset=3Dwindows-1252"
http-equiv=3D"Content-Type">
</head>
<body bgcolor=3D"#FFFFFF" text=3D"#000000">
<div class=3D"moz-cite-prefix">Le 31/12/2015 08:52, Giovanni Piero
Deretta a =C3=A9crit=C2=A0:<br>
</div>
<blockquote
cite=3D"mid:7dd984a6-9002-4e19-8964-23a523efeed2@isocpp.org"
type=3D"cite">On Wednesday, December 30, 2015 at 4:37:39 PM UTC,
Vicente J. Botet Escriba wrote:
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<div bgcolor=3D"#FFFFFF" text=3D"#000000">
<div>Le 30/12/2015 15:24, Giovanni Piero Deretta a =C3=A9crit=C2=
=A0:<br>
</div>
<blockquote type=3D"cite">On Wednesday, December 30, 2015 at
1:20:35 PM UTC, Vicente J. Botet Escriba wrote:
<blockquote class=3D"gmail_quote"
style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc
solid;padding-left:1ex">
<div bgcolor=3D"#FFFFFF" text=3D"#000000"> [...]<br>
I'm getting a compile error while trying to return an
unnamed struct from a function (I don't know where in
the standard this limitation appears)<br>
<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 struct {=C2=A0=C2=A0 // ERRO=
R<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int =
first;<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int =
second;<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 a_pair()<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 {<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return {1, -1};<=
br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }<br>
<br>
error: '(anonymous struct at pair_pass.cpp:91:7)' cannot
be defined in the result type of a function<br>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 struct {<br>
<br>
[...]<br>
Is there any reason to don't support functions/lambdas
returning unnamed structs?<br>
</div>
</blockquote>
<div><br>
This works in C++14:<br>
<br>
auto a_pair ()<br>
{<br>
=C2=A0=C2=A0 struct { int first; int second; } r {0, 1};<br>
=C2=A0=C2=A0 return r;<br>
}<br>
<br>
Is this similar to what you had in mind?<br>
</div>
</blockquote>
Hmm, yes and not. This works if the function body is in the
declaration. However, it is not practical to define an
interface in the standard :(<br>
<br>
</div>
</blockquote>
<div><br>
hum, what's the problem exactly? As far as I understand, the use
case is range algorithms, i.e. template functions which are in
practice always defined inline.=C2=A0 The standard spec would simpl=
y
say that these algorithms return an unspecified type which has
certain properties.<br>
<br>
</div>
</blockquote>
You are right for this specific use case. However I suspect that the
wording sating that the user just can access the parts and can do
nothing with the global result will be not enough.<br>
<br>
As Tony as signaled, unnamed structs are different types on the same
translation unit. <br>
<br>
Given
<div><br>
</div>
<div class=3D"prettyprint" style=3D"border: 1px solid rgb(187, 187,
187); word-wrap: break-word; background-color: rgb(250, 250,
250);"><code class=3D"prettyprint">
<div class=3D"subprettyprint"><span style=3D"color: #008;"
class=3D"styled-by-prettify">struct</span><span style=3D"color:
#000;" class=3D"styled-by-prettify"> </span><span
style=3D"color: #660;" class=3D"styled-by-prettify">{</span><sp=
an
style=3D"color: #000;" class=3D"styled-by-prettify"> </span><sp=
an
style=3D"color: #008;" class=3D"styled-by-prettify">int</span><=
span
style=3D"color: #000;" class=3D"styled-by-prettify"> i</span><s=
pan
style=3D"color: #660;" class=3D"styled-by-prettify">;</span><sp=
an
style=3D"color: #000;" class=3D"styled-by-prettify"> </span><sp=
an
style=3D"color: #660;" class=3D"styled-by-prettify">}</span><sp=
an
style=3D"color: #000;" class=3D"styled-by-prettify"> a</span><s=
pan
style=3D"color: #660;" class=3D"styled-by-prettify">,</span><sp=
an
style=3D"color: #000;" class=3D"styled-by-prettify"> 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">=
struct</span><span
style=3D"color: #000;" class=3D"styled-by-prettify"> </span><sp=
an
style=3D"color: #660;" class=3D"styled-by-prettify">{</span><sp=
an
style=3D"color: #000;" class=3D"styled-by-prettify"> </span><sp=
an
style=3D"color: #008;" class=3D"styled-by-prettify">int</span><=
span
style=3D"color: #000;" class=3D"styled-by-prettify"> i</span><s=
pan
style=3D"color: #660;" class=3D"styled-by-prettify">;</span><sp=
an
style=3D"color: #000;" class=3D"styled-by-prettify"> </span><sp=
an
style=3D"color: #660;" class=3D"styled-by-prettify">}</span><sp=
an
style=3D"color: #000;" class=3D"styled-by-prettify"> bar</span>=
<span
style=3D"color: #660;" class=3D"styled-by-prettify">();</span><=
/div>
</code></div>
<div><br>
</div>
can you write `a =3D bar();`? <br>
<br>
Something must be changed to consider unnamed structs (or something
else) to have the same type if the parts are the same. <br>
If this issue is solved and if IRTVPDUA proposal was adopted, the
interface could even use the unnamed struct. <br>
<br>
Vicente<br>
</body>
</html>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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"https://groups.google.com/a/isocpp.org/group=
/std-proposals/">https://groups.google.com/a/isocpp.org/group/std-proposals=
/</a>.<br />
--------------050607000500030401010608--
.
Author: "Vicente J. Botet Escriba" <vicente.botet@wanadoo.fr>
Date: Sun, 3 Jan 2016 11:35:29 +0100
Raw View
This is a multi-part message in MIME format.
--------------020202050002040104080600
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: quoted-printable
Le 03/01/2016 04:07, Nicol Bolas a =C3=A9crit :
> On Wednesday, December 30, 2015 at 8:20:35 AM UTC-5, Vicente J. Botet=20
> Escriba wrote:
>
> Hi,
>
> n4560 introduce the classes tagged, tagged_pair and tagged_tuple.
> Here follows the rationale as described in n4560:
>
> /[Editor=E2=80=99s note: This type exists so that the algorithms can
> return pair- and tuple-like objects with named accessors, as
> requested by LEWG. Rather than create a bunch of one-off class
> types with no relation to pair and tuple, I opted instead to
> create a general utility. I=E2=80=99ll note that this functionality c=
an be
> merged into pair and tuple directly with minimal breakage, but I
> opted for now to keep it separate.]//
> /
>
> I was wondering if
>
> tagged_pair<tag::in(I), tag::fun(Fun)>
>
> couldn't be better be represented by the unnamed aggregate
>
> struct {
> I in;
> Fun fun;
> }
>
> which has less noise.
>
>
> Here's a question.
>
> From my perspective, the principle reason to use a tuple is=20
> /metaprogramming/. That is, you're assembling an aggregation of values=20
> from some some user-provided construct. A tagged tuple has limited=20
> metaprogramming value, but it still has some value in that regard. By=20
> tagging types with names, you can develop interfaces between the=20
> sender and the receiver of a tuple that allow you to more effectively=20
> communicate. Rather than communicating by type or index, you=20
> communicate by a name, thus giving the sending code the freedom to=20
> pick and choose where the element is in the tuple.
>
> That's the reason why we need tagged tuples, and the above case won't=20
> even touch that one. Reflection-based aggregate creation might fix it,=20
> but that's for C++20, if even that.
>
> Using a tuple for plain-old multiple-return-values has always been, to=20
> me, of somewhat dubious merit. It's not a terrible, and it's a=20
> solution that'll be far more acceptable with structured binding. But=20
> using a /tagged/ tuple as a return value from a concrete function? No;=20
> that makes no sense.
>
> Clearly you should be returning a struct. But that's where I don't get=20
> the point of this proposal. Because, well, why does it /have to be/=20
> "unnamed"? I mean, are names /that precious/ that we need to have=20
> specialized syntax to do this? Is this:
>
> |
> struct{intx;floaty}func(){...}
> |
>
> Really that much better than this?
>
> |
> structMeaningfulName{intx;floaty};
>
> MeaningfulNamefunc(){...}
> |
>
> If the type returned by this function needs to name the individual=20
> multiple values, then that aggregation of values probably has some=20
> meaning. 9 times out of 10, other functions will want to return that=20
> same type. So you're going to need a named type.
Here is the problem of naming the result type. When we talk of returning=20
several values is because we don't have yet one type to aggregate them.=20
Most of the time a name is is not meaningful.
Think of it as if we had a single parameter with all the input values of=20
a function call. Giving a name would be most of the time not=20
meaningful. We just have instead several parameters.
>
> Just consider the main confounding problem of this proposal:
>
> |
> struct{intx;floaty}other_func(){...}
> struct{intx;floaty}func(){returnother_func();}
> |
>
> Even if we found a way to make this work, I don't really want to /see=20
> it/. When I look at this code, I see repetition; I see the same type=20
> being written twice. I see someone who has not created a named type=20
> who clearly /ought to/.
Do you prefer to name it ResultType_for_func_and_other_func? No, off course=
..
IMO product types are as natural as parameters of a function than as=20
result of a function. We don't want to name them.
>
> After all, what is the point of assigning names to the members of the=20
> return value? It's so that the receiver of the object knows what those=20
> values mean. So that we don't have the `map::insert` idiocy where=20
> "ret.second" is what tells you whether the object was correctly inserted.
unnamed struct give exactly that.
>
> If so... you need a struct. A /named/ struct. `std::map` proves that,=20
> since it has several interface functions that all return the same=20
> `pair<iterator, bool>`, and all of them have the same meaning (the=20
> bool tells whether insertion happened, the iterator says where the=20
> element is). If two types have the same functionality and meaning,=20
> they are the same type.
Waiting for your proposal to change this ;-)
>
> And in C++, we declare two types to be the same by giving them the=20
> same name.
Right.
>
> So it seems to me that unnamed struct return values would only be=20
> useful in cases where:
>
> 1) `tuple` is inappropriate. This would suggest that the semantic=20
> meaning of each independent return value is both significant and not=20
> obvious from just the type and function name (`pair` returned from=20
> `map::insert` is a good example). And `tagged_tuple`, well, sucks at=20
> this for obvious reasons.
Agreed.
>
> 2) That function is the /only function/ that returns this type or does=20
> anything with it in any way. If the function has even one other=20
> overload, then you ought to use a named type.
>
I don't agree here. Each function independently have its output. If the=20
output has already a name in the domain, we just use it. Otherwise there=20
is no need to find artificial names.
> How often do you encounter both #1 and #2? Is this often enough to=20
> justify such a language feature? With structured binding making tuples=20
> far more usable for MRV than they have ever been, I just can't=20
> understand why we need unnamed struct returns like this.
Take in account that a lot of the current code is written using=20
references as output parameters. Things are changing since move=20
semantics, RTO, ...
I will replay to you with another questions.
How many times do you find 1) is useful?
I have not found a single one at the user level.
How many times do you have a function that has more than one output=20
parameters (result)?
Much more than we used to have.
So, if the question you are raising is if it is worth doing something so=20
that we can solve this multiple-value return,
I believe the the answer of the standard committee is yes, otherwise we=20
will not have tagged tuples, structural bindings, ...
Granted unnamed structs can not be used as such (this is already=20
admitted in previous posts).
So the question I'm raising is if we want something as simple as=20
possible (at the user level, not at the standard level) to mean=20
multiple values returned by a function
After some insignt, I believe that even the keyword could be removed ;-)
| {intx;floaty}other_func(int a, int b) {...}
|
| auto other_func(int a, int b)-> |||{intx;floaty} |{...}
|
Note the symmetry between parameter and results (almost symmetric).
Vicente
P.S. Note that I'm not against giving a name to an aggregation when the=20
aggregation has more meaning than just its parts.
--=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 https://groups.google.com/a/isocpp.org/group/std-propos=
als/.
--------------020202050002040104080600
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta content=3D"text/html; charset=3Dwindows-1252"
http-equiv=3D"Content-Type">
</head>
<body bgcolor=3D"#FFFFFF" text=3D"#000000">
<div class=3D"moz-cite-prefix">Le 03/01/2016 04:07, Nicol Bolas a
=C3=A9crit=C2=A0:<br>
</div>
<blockquote
cite=3D"mid:fbeac322-b99b-430a-98ae-7a941828dc7c@isocpp.org"
type=3D"cite">On Wednesday, December 30, 2015 at 8:20:35 AM UTC-5,
Vicente J. Botet Escriba wrote:
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<div bgcolor=3D"#FFFFFF" text=3D"#000000"> Hi,<br>
<br>
n4560 introduce the classes tagged, tagged_pair and
tagged_tuple. Here follows the rationale as described in
n4560:<br>
<br>
<i>[Editor=E2=80=99s note: This type exists so that the algorithm=
s can
return pair- and tuple-like objects with named accessors, as
requested by LEWG. Rather than create a bunch of one-off
class types with no relation to pair and tuple, I opted
instead to create a general utility. I=E2=80=99ll note that thi=
s
functionality can be merged into pair and tuple directly
with minimal breakage, but I opted for now to keep it
separate.]</i><i><br>
</i><br>
<br>
I was wondering if<br>
<br>
=C2=A0=C2=A0=C2=A0 tagged_pair<tag::in(I), tag::fun(Fun)><b=
r>
<br>
couldn't be better be represented by the unnamed aggregate<br>
<br>
=C2=A0=C2=A0=C2=A0 struct {<br>
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 I in;<br>
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 Fun fun;<br>
=C2=A0=C2=A0=C2=A0 }<br>
<br>
which has less noise.<br>
</div>
</blockquote>
<br>
Here's a question.<br>
<br>
From my perspective, the principle reason to use a tuple is <i>metapr=
ogramming</i>.
That is, you're assembling an aggregation of values from some some
user-provided construct. A tagged tuple has limited
metaprogramming value, but it still has some value in that regard.
By tagging types with names, you can develop interfaces between
the sender and the receiver of a tuple that allow you to more
effectively communicate. Rather than communicating by type or
index, you communicate by a name, thus giving the sending code the
freedom to pick and choose where the element is in the tuple.<br>
<br>
That's the reason why we need tagged tuples, and the above case
won't even touch that one. Reflection-based aggregate creation
might fix it, but that's for C++20, if even that.<br>
<br>
Using a tuple for plain-old multiple-return-values has always
been, to me, of somewhat dubious merit. It's not a terrible, and
it's a solution that'll be far more acceptable with structured
binding. But using a <i>tagged</i> tuple as a return value from a
concrete function? No; that makes no sense.<br>
<br>
Clearly you should be returning a struct. But that's where I don't
get the point of this proposal. Because, well, why does it <i>have
to be</i> "unnamed"? I mean, are names <i>that precious</i>
that we need to have specialized syntax to do this? Is this:<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-prettify">struct</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: #008;" class=3D"styled-by-prettify">int</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"styled-by-prettify"> </span><=
span
style=3D"color: #008;" class=3D"styled-by-prettify">float</sp=
an><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"> func</sp=
an><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: #660;" class=3D"styled-by-prettify">{...}</sp=
an></div>
</code></div>
<br>
Really that much better than this?<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-prettify">struct</span><span
style=3D"color: #000;" class=3D"styled-by-prettify"> </span><=
span
style=3D"color: #606;" class=3D"styled-by-prettify">Meaningfu=
lName</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: #008;" class=3D"styled-by-prettify">int</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"styled-by-prettify"> </span><=
span
style=3D"color: #008;" class=3D"styled-by-prettify">float</sp=
an><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"><br>
<br>
</span><span style=3D"color: #606;" class=3D"styled-by-prettify=
">MeaningfulName</span><span
style=3D"color: #000;" class=3D"styled-by-prettify"> func</sp=
an><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: #660;" class=3D"styled-by-prettify">{...}</sp=
an></div>
</code></div>
<br>
If the type returned by this function needs to name the individual
multiple values, then that aggregation of values probably has some
meaning. 9 times out of 10, other functions will want to return
that same type. So you're going to need a named type.<br>
</blockquote>
Here is the problem of naming the result type. When we talk of
returning several values is because we don't have yet one type to
aggregate them. Most of the time a name is is not meaningful.<br>
<br>
Think of it as if we had a single parameter with all the input
values of a function call. Giving a name would be most of the time
not meaningful.=C2=A0 We just have instead several parameters. =C2=A0 <=
br>
<blockquote
cite=3D"mid:fbeac322-b99b-430a-98ae-7a941828dc7c@isocpp.org"
type=3D"cite"><br>
Just consider the main confounding problem of this proposal:<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-prettify">struct</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: #008;" class=3D"styled-by-prettify">int</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"styled-by-prettify"> </span><=
span
style=3D"color: #008;" class=3D"styled-by-prettify">float</sp=
an><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">
other_func</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: #660;" class=3D"styled-by-prettify">{...}</sp=
an><span
style=3D"color: #000;" class=3D"styled-by-prettify"><br>
</span><span style=3D"color: #008;" class=3D"styled-by-prettify=
">struct</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: #008;" class=3D"styled-by-prettify">int</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"styled-by-prettify"> </span><=
span
style=3D"color: #008;" class=3D"styled-by-prettify">float</sp=
an><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"> func</sp=
an><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: #660;" class=3D"styled-by-prettify">{</span><=
span
style=3D"color: #008;" class=3D"styled-by-prettify">return</s=
pan><span
style=3D"color: #000;" class=3D"styled-by-prettify">
other_func</span><span style=3D"color: #660;"
class=3D"styled-by-prettify">();}</span></div>
</code></div>
<br>
Even if we found a way to make this work, I don't really want to <i>s=
ee
it</i>. When I look at this code, I see repetition; I see the
same type being written twice. I see someone who has not created a
named type who clearly <i>ought to</i>.<br>
</blockquote>
Do you prefer to name it ResultType_for_func_and_other_func? No, off
course.<br>
<br>
IMO product types are as natural as parameters of a function than as
result of a function. We don't want to name them.<br>
<br>
<blockquote
cite=3D"mid:fbeac322-b99b-430a-98ae-7a941828dc7c@isocpp.org"
type=3D"cite"><br>
After all, what is the point of assigning names to the members of
the return value? It's so that the receiver of the object knows
what those values mean. So that we don't have the `<a class=3D"moz-tx=
t-link-freetext" href=3D"map::insert">map::insert</a>`
idiocy where "ret.second" is what tells you whether the object was
correctly inserted.<br>
</blockquote>
unnamed struct give exactly that.<br>
<blockquote
cite=3D"mid:fbeac322-b99b-430a-98ae-7a941828dc7c@isocpp.org"
type=3D"cite"><br>
If so... you need a struct. A <i>named</i> struct. `std::map`
proves that, since it has several interface functions that all
return the same `pair<iterator, bool>`, and all of them have
the same meaning (the bool tells whether insertion happened, the
iterator says where the element is). If two types have the same
functionality and meaning, they are the same type.<br>
</blockquote>
Waiting for your proposal to change this ;-)<br>
<blockquote
cite=3D"mid:fbeac322-b99b-430a-98ae-7a941828dc7c@isocpp.org"
type=3D"cite"><br>
And in C++, we declare two types to be the same by giving them the
same name.<br>
</blockquote>
Right.<br>
<blockquote
cite=3D"mid:fbeac322-b99b-430a-98ae-7a941828dc7c@isocpp.org"
type=3D"cite"><br>
So it seems to me that unnamed struct return values would only be
useful in cases where:<br>
<br>
1) `tuple` is inappropriate. This would suggest that the semantic
meaning of each independent return value is both significant and
not obvious from just the type and function name (`pair` returned
from `<a class=3D"moz-txt-link-freetext" href=3D"map::insert">map::in=
sert</a>` is a good example). And `tagged_tuple`, well,
sucks at this for obvious reasons.<br>
</blockquote>
Agreed.<br>
<blockquote
cite=3D"mid:fbeac322-b99b-430a-98ae-7a941828dc7c@isocpp.org"
type=3D"cite"><br>
2) That function is the <i>only function</i> that returns this
type or does anything with it in any way. If the function has even
one other overload, then you ought to use a named type.<br>
<br>
</blockquote>
I don't agree here. Each function independently have its output. If
the output has already a name in the domain, we just use it.
Otherwise there is no need to find artificial names.<br>
<blockquote
cite=3D"mid:fbeac322-b99b-430a-98ae-7a941828dc7c@isocpp.org"
type=3D"cite">How often do you encounter both #1 and #2? Is this
often enough to justify such a language feature? With structured
binding making tuples far more usable for MRV than they have ever
been, I just can't understand why we need unnamed struct returns
like this.<br>
</blockquote>
Take in account that a lot of the current code is written using
references as output parameters. Things are changing since move
semantics, RTO, ...<br>
<br>
I will replay to you with another questions.<br>
<br>
How many times do you find 1) is useful?<br>
=C2=A0=C2=A0=C2=A0 I have not found a single one at the user level.<br>
<br>
How many times do you have a function that has more than one output
parameters (result)?<br>
=C2=A0=C2=A0=C2=A0 Much more than we used to have.<br>
<br>
So, if the question you are raising is if it is worth doing
something so that we can solve this multiple-value return, <br>
I believe the the answer of the standard committee is yes, otherwise
we will not have tagged tuples, structural bindings, ...<br>
<br>
Granted unnamed structs can not be used as such (this is already
admitted in previous posts). <br>
So the question I'm raising is if we want something as simple as
possible (at the user level, not at the standard level)=C2=A0 to mean
multiple values returned by a function<br>
<br>
After some insignt, I believe that even the keyword could be removed
;-)<br>
<br>
<code class=3D"prettyprint"><span style=3D"color: #000;"
class=3D"styled-by-prettify"></span><span style=3D"color: #660;"
class=3D"styled-by-prettify">=C2=A0=C2=A0=C2=A0 {</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><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">float</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"> other_func</sp=
an><span
style=3D"color: #660;" class=3D"styled-by-prettify">(int a, int b)<=
/span><span
style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span
style=3D"color: #660;" class=3D"styled-by-prettify">=C2=A0=C2=A0=C2=
=A0 {...}</span><span
style=3D"color: #000;" class=3D"styled-by-prettify"><br>
</span></code><br>
<code class=3D"prettyprint"><span style=3D"color: #660;"
class=3D"styled-by-prettify">=C2=A0=C2=A0=C2=A0 auto </span><span s=
tyle=3D"color:
#000;" class=3D"styled-by-prettify">other_func</span><span
style=3D"color: #660;" class=3D"styled-by-prettify">(int a, int b)<=
/span><span
style=3D"color: #000;" class=3D"styled-by-prettify"> -> </span><=
/code><code
class=3D"prettyprint"><span style=3D"color: #000;"
class=3D"styled-by-prettify"><code class=3D"prettyprint"><span
style=3D"color: #660;" class=3D"styled-by-prettify">{</span><sp=
an
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><sp=
an
style=3D"color: #000;" class=3D"styled-by-prettify"> </span><sp=
an
style=3D"color: #008;" class=3D"styled-by-prettify">float</span=
><span
style=3D"color: #000;" class=3D"styled-by-prettify"> y</span><s=
pan
style=3D"color: #660;" class=3D"styled-by-prettify">}=C2=A0=C2=
=A0=C2=A0 </span></code></span><span
style=3D"color: #660;" class=3D"styled-by-prettify">{...}</span><sp=
an
style=3D"color: #000;" class=3D"styled-by-prettify"><br>
</span></code><br>
Note the symmetry between parameter and results (almost symmetric).<br>
<br>
Vicente<br>
<br>
P.S. Note that I'm not against giving a name to an aggregation when
the aggregation has more meaning than just its parts.<br>
<br>
<br>
</body>
</html>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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"https://groups.google.com/a/isocpp.org/group=
/std-proposals/">https://groups.google.com/a/isocpp.org/group/std-proposals=
/</a>.<br />
--------------020202050002040104080600--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sun, 3 Jan 2016 09:12:21 -0800 (PST)
Raw View
------=_Part_6026_1424375795.1451841141189
Content-Type: multipart/alternative;
boundary="----=_Part_6027_1431846074.1451841141199"
------=_Part_6027_1431846074.1451841141199
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Sunday, January 3, 2016 at 5:35:33 AM UTC-5, Vicente J. Botet Escriba=20
wrote:
>
> Le 03/01/2016 04:07, Nicol Bolas a =C3=A9crit :
>
> On Wednesday, December 30, 2015 at 8:20:35 AM UTC-5, Vicente J. Botet=20
> Escriba wrote:=20
>>
>> Hi,
>>
>> n4560 introduce the classes tagged, tagged_pair and tagged_tuple. Here=
=20
>> follows the rationale as described in n4560:
>>
>> *[Editor=E2=80=99s note: This type exists so that the algorithms can ret=
urn pair-=20
>> and tuple-like objects with named accessors, as requested by LEWG. Rathe=
r=20
>> than create a bunch of one-off class types with no relation to pair and=
=20
>> tuple, I opted instead to create a general utility. I=E2=80=99ll note th=
at this=20
>> functionality can be merged into pair and tuple directly with minimal=20
>> breakage, but I opted for now to keep it separate.]*
>>
>>
>> I was wondering if
>>
>> tagged_pair<tag::in(I), tag::fun(Fun)>
>>
>> couldn't be better be represented by the unnamed aggregate
>>
>> struct {
>> I in;
>> Fun fun;
>> }
>>
>> which has less noise.
>>
>
> Here's a question.
>
> From my perspective, the principle reason to use a tuple is=20
> *metaprogramming*. That is, you're assembling an aggregation of values=20
> from some some user-provided construct. A tagged tuple has limited=20
> metaprogramming value, but it still has some value in that regard. By=20
> tagging types with names, you can develop interfaces between the sender a=
nd=20
> the receiver of a tuple that allow you to more effectively communicate.=
=20
> Rather than communicating by type or index, you communicate by a name, th=
us=20
> giving the sending code the freedom to pick and choose where the element =
is=20
> in the tuple.
>
> That's the reason why we need tagged tuples, and the above case won't eve=
n=20
> touch that one. Reflection-based aggregate creation might fix it, but=20
> that's for C++20, if even that.
>
> Using a tuple for plain-old multiple-return-values has always been, to me=
,=20
> of somewhat dubious merit. It's not a terrible, and it's a solution that'=
ll=20
> be far more acceptable with structured binding. But using a *tagged*=20
> tuple as a return value from a concrete function? No; that makes no sense=
..
>
> Clearly you should be returning a struct. But that's where I don't get th=
e=20
> point of this proposal. Because, well, why does it *have to be*=20
> "unnamed"? I mean, are names *that precious* that we need to have=20
> specialized syntax to do this? Is this:
>
> struct {int x; float y} func() {...}
>
> Really that much better than this?
>
> struct MeaningfulName {int x; float y};
>
> MeaningfulName func() {...}
>
> If the type returned by this function needs to name the individual=20
> multiple values, then that aggregation of values probably has some meanin=
g.=20
> 9 times out of 10, other functions will want to return that same type. So=
=20
> you're going to need a named type.
>
> Here is the problem of naming the result type. When we talk of returning=
=20
> several values is because we don't have yet one type to aggregate them.=
=20
> Most of the time a name is is not meaningful.
>
See, that right there is what I do not believe. It has not been my=20
experience that the name of such an aggregation "is not meaningful".
Remember, we're not talking about a throwaway MRV case where you would use=
=20
a tuple nowadays. We're talking about an MRV case where the individual=20
return values *need* a semantic name, where the mere type or position of=20
the value does not indicate its meaning. That's not all or even most MRV=20
cases.
`map::insert` is a good example, because `pair<iterator, bool>` is really=
=20
impenetrable as to its meaning. The `iterator`, you can figure out what=20
that probably means. But the `bool` is completely meaningless; you have to=
=20
look up the documentation to know what it means.
So in a better designed system, this would be a struct with two members.=20
You say that the name of such a struct "is not meaningful". I contest this.=
=20
A decent name for such a struct would be "insertion_state". That's what it=
=20
is and that's what it is used for: telling you the state of the system=20
after insertion. That name is meaningful.
I don't think whether the name is meaningful is a good litmus test for your=
=20
case. I think a better one is this: what is the likelihood that a user will=
=20
want to keep that aggregate around *as an aggregate*. That is, would a user=
=20
be willing to pass it around to other functions? Not just as pass-through=
=20
return values, but as a parameter to some other function. Will the user=20
store it in some type for longer-duration keeping?
It is in this case where `insertion_state` has dubious merit. Because...=20
well, I can't see a real reason why I would write a function that takes it=
=20
as a parameter. The two fields basically have nothing to do with one=20
another. Nor could I see a reason to store one in a larger data structure.=
=20
The `iterator`, I could understand keeping around. But the `bool` has value=
=20
only to the immediate caller of the insertion operation. The farther you=20
are from that operation, the less likely you will care whether it actually=
=20
inserted the object or not.
So what we're talking about is an aggregation who's nature is ephemeral, of=
=20
the moment. It's not that the aggregation's name is meaningless; it's that=
=20
the aggregation *itself* is meaningless. That the aggregation exists solely=
=20
as a workaround to the lack of MRV support in the language.
But then, that comes back to my two points. For this to matter, you have to=
=20
have a meaningless aggregation and types which don't explain what they=20
mean. After all, the only reason you want to name the return value at all=
=20
is because the `bool` argument is unclear as to its meaning. If it were=20
instead:
enum class did_insert : unsigned char
{
no_insert =3D 0,
inserted,
};
pair<iterator, did_insert> insert(...);
Then the tuple/pair would be perfectly fine. Both values make it clear what=
=20
they mean simply from their types. So there is no need to name them.
So, here's what I would like to see. Give me a case where the aggregation=
=20
is clearly ephemeral, yet the meaning of the individual values cannot be=20
inferred from the nature of the function and the typenames of those values.=
=20
`map::insert` is problematic only because it use `bool`; if it had used a=
=20
more expressive typename, it would have been fine.
I imagine such cases would be limited to things like a version stoi that=20
returned multiple values instead of an optional output parameter. The=20
aggregation is clearly ephemeral, but the return values are just basic=20
integer types, without obvious meaning. It seems to me that this problem=20
primarily occurs when the return types are basic types, which have no=20
inherent meaning provided by the function.
This is a place where weak aliases (a distinct type from the original, but=
=20
implicitly convertible to/from) could be of value. So stoi could look like:
using pos_offset =3D ... //Weak alias of `size_t`.
pair<int, pos_offset> stoi(string_span str, int base =3D 10);
This gives us clear semantic meaning. The second value is a position=20
offset, so the first value, by process of elimination, must be the=20
converted integer.
So it seems to me that in these cases, better aliasing support could get=20
allow us to get past these issues. We wouldn't need named return values so=
=20
much if the types had more meaning.
Think of it as if we had a single parameter with all the input values of a=
=20
> function call. Giving a name would be most of the time not meaningful. W=
e=20
> just have instead several parameters.
>
And if multiple return values were anywhere near as common as multiple=20
parameters, your argument might have some weight.
> Just consider the main confounding problem of this proposal:
>
> struct {int x; float y} other_func() {...}
> struct {int x; float y} func() {return other_func();}
>
> Even if we found a way to make this work, I don't really want to *see it*=
..=20
> When I look at this code, I see repetition; I see the same type being=20
> written twice. I see someone who has not created a named type who clearly=
*ought=20
> to*.
>
> Do you prefer to name it ResultType_for_func_and_other_func?
>
Obvious strawman arguments aren't helping your case.
> After all, what is the point of assigning names to the members of the=20
> return value? It's so that the receiver of the object knows what those=20
> values mean. So that we don't have the `map::insert` idiocy where=20
> "ret.second" is what tells you whether the object was correctly inserted.
>
> unnamed struct give exactly that.
>
So would a *named* struct, which requires zero language changes.
> If so... you need a struct. A *named* struct. `std::map` proves that,=20
> since it has several interface functions that all return the same=20
> `pair<iterator, bool>`, and all of them have the same meaning (the bool=
=20
> tells whether insertion happened, the iterator says where the element is)=
..=20
> If two types have the same functionality and meaning, they are the same=
=20
> type.
>
> Waiting for your proposal to change this ;-)
>
To change what?
> How often do you encounter both #1 and #2? Is this often enough to justif=
y=20
> such a language feature? With structured binding making tuples far more=
=20
> usable for MRV than they have ever been, I just can't understand why we=
=20
> need unnamed struct returns like this.
>
> Take in account that a lot of the current code is written using reference=
s=20
> as output parameters. Things are changing since move semantics, RTO, ...
>
.... I don't really know what you're getting at with this statement.
=20
> I will replay to you with another questions.
>
> How many times do you find 1) is useful?
> I have not found a single one at the user level.
>
> How many times do you have a function that has more than one output=20
> parameters (result)?
> Much more than we used to have.
>
For me? Not very often. Indeed, almost never. Maybe my C++ experience=20
causes me to subconsciously design *around* the limitations of single=20
return values, but I have rarely written functions where I have felt a=20
genuine need to return multiple things. Perhaps if I had a functional=20
programming background, I'd use them more frequently. But for me, MRV is=20
not particularly common.
My experience with Lua, which has native (and very cool) support for=20
multiple return values, bears this out. In that language, I have used MRVs=
=20
more frequently than tuple return values in C++. But at the same time, I=20
have pretty much never wanted to name *individual return values*. In=20
virtually every case, what the multiple values meant was readily apparent;=
=20
there was no need to give each one a semantic name.
And if there was a need, then I returned a Lua table with named fields.=20
Now, this is where the analogy breaks down, because Lua doesn't have static=
=20
types. But I wouldn't have had any problem giving those aggregations of=20
values a name.
You say that you use MRVs more frequently than you used to. Why? What is=20
your code doing that needs to throw around multiple values like this? It is=
=20
not clear to me what has changed that causes you to code like this.
So, if the question you are raising is if it is worth doing something so=20
> that we can solve this multiple-value return,=20
> I believe the the answer of the standard committee is yes, otherwise we=
=20
> will not have tagged tuples, structural bindings, ...
>
Structured bindings and tagged tuples are two completely different things.=
=20
Structured binding doesn't even have to do with naming return values, since=
=20
it's the *receiver* who is giving it a meaningful name. A name that notably=
=20
could be *wrong*. Indeed, if you call a function that returns named MRVs,=
=20
you *shouldn't use* structured bindings on the return value (most of the=20
time). You'd just use the aggregation directly, accessing the member fields=
=20
using the convenient names.
P.S. Note that I'm not against giving a name to an aggregation when the=20
> aggregation has more meaning than just its parts.
>
As a general courtesy to my users, if I have to return a `pair` or `tuple`=
=20
for MRVs, I wrap it in a typedef, so they don't have to type the whole=20
thing themselves. I give names to meaningless, ephemeral aggregations all=
=20
the time.
--=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 https://groups.google.com/a/isocpp.org/group/std-propos=
als/.
------=_Part_6027_1431846074.1451841141199
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Sunday, January 3, 2016 at 5:35:33 AM UTC-5, Vicente J. Botet Escriba wr=
ote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;">
=20
=20
=20
<div bgcolor=3D"#FFFFFF" text=3D"#000000">
<div>Le 03/01/2016 04:07, Nicol Bolas a
=C3=A9crit=C2=A0:<br>
</div>
<blockquote type=3D"cite">On Wednesday, December 30, 2015 at 8:20:35 AM=
UTC-5,
Vicente J. Botet Escriba wrote:
<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex=
;border-left:1px #ccc solid;padding-left:1ex">
<div bgcolor=3D"#FFFFFF" text=3D"#000000"> Hi,<br>
<br>
n4560 introduce the classes tagged, tagged_pair and
tagged_tuple. Here follows the rationale as described in
n4560:<br>
<br>
<i>[Editor=E2=80=99s note: This type exists so that the algorithm=
s can
return pair- and tuple-like objects with named accessors, as
requested by LEWG. Rather than create a bunch of one-off
class types with no relation to pair and tuple, I opted
instead to create a general utility. I=E2=80=99ll note that thi=
s
functionality can be merged into pair and tuple directly
with minimal breakage, but I opted for now to keep it
separate.]</i><i><br>
</i><br>
<br>
I was wondering if<br>
<br>
=C2=A0=C2=A0=C2=A0 tagged_pair<tag::in(I), tag::fun(Fun)><b=
r>
<br>
couldn't be better be represented by the unnamed aggregate<br=
>
<br>
=C2=A0=C2=A0=C2=A0 struct {<br>
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 I in;<br>
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 Fun fun;<br>
=C2=A0=C2=A0=C2=A0 }<br>
<br>
which has less noise.<br>
</div>
</blockquote>
<br>
Here's a question.<br>
<br>
From my perspective, the principle reason to use a tuple is <i>metapr=
ogramming</i>.
That is, you're assembling an aggregation of values from some som=
e
user-provided construct. A tagged tuple has limited
metaprogramming value, but it still has some value in that regard.
By tagging types with names, you can develop interfaces between
the sender and the receiver of a tuple that allow you to more
effectively communicate. Rather than communicating by type or
index, you communicate by a name, thus giving the sending code the
freedom to pick and choose where the element is in the tuple.<br>
<br>
That's the reason why we need tagged tuples, and the above case
won't even touch that one. Reflection-based aggregate creation
might fix it, but that's for C++20, if even that.<br>
<br>
Using a tuple for plain-old multiple-return-values has always
been, to me, of somewhat dubious merit. It's not a terrible, and
it's a solution that'll be far more acceptable with structure=
d
binding. But using a <i>tagged</i> tuple as a return value from a
concrete function? No; that makes no sense.<br>
<br>
Clearly you should be returning a struct. But that's where I don&=
#39;t
get the point of this proposal. Because, well, why does it <i>have
to be</i> "unnamed"? I mean, are names <i>that precious</=
i>
that we need to have specialized syntax to do this? Is this:<br>
<br>
<div 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>
<div><span style=3D"color:#008">struct</span><span style=3D"color=
:#000"> </span><span style=3D"color:#660">{</span><span style=3D"color:#008=
">int</span><span style=3D"color:#000"> x</span><span style=3D"color:#660">=
;</span><span style=3D"color:#000"> </span><span style=3D"color:#008">float=
</span><span style=3D"color:#000"> y</span><span style=3D"color:#660">}</sp=
an><span style=3D"color:#000"> func</span><span style=3D"color:#660">()</sp=
an><span style=3D"color:#000"> </span><span style=3D"color:#660">{...}</spa=
n></div>
</code></div>
<br>
Really that much better than this?<br>
<br>
<div 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>
<div><span style=3D"color:#008">struct</span><span style=3D"color=
:#000"> </span><span style=3D"color:#606">MeaningfulName</span><span style=
=3D"color:#000"> </span><span style=3D"color:#660">{</span><span style=3D"c=
olor:#008">int</span><span style=3D"color:#000"> x</span><span style=3D"col=
or:#660">;</span><span style=3D"color:#000"> </span><span style=3D"color:#0=
08">float</span><span style=3D"color:#000"> y</span><span style=3D"color:#6=
60">};</span><span style=3D"color:#000"><br>
<br>
</span><span style=3D"color:#606">MeaningfulName</span><span st=
yle=3D"color:#000"> func</span><span style=3D"color:#660">()</span><span st=
yle=3D"color:#000"> </span><span style=3D"color:#660">{...}</span></div>
</code></div>
<br>
If the type returned by this function needs to name the individual
multiple values, then that aggregation of values probably has some
meaning. 9 times out of 10, other functions will want to return
that same type. So you're going to need a named type.<br>
</blockquote>
Here is the problem of naming the result type. When we talk of
returning several values is because we don't have yet one type to
aggregate them. Most of the time a name is is not meaningful.<br></div>=
</blockquote><div><br>See, that right there is what I do not believe. It ha=
s not been my experience that the name of such an aggregation "is not =
meaningful".<br><br>Remember, we're not talking about a throwaway =
MRV case where you would use a tuple nowadays. We're talking about an M=
RV case where the individual return values <i>need</i> a semantic name, whe=
re the mere type or position of the value does not indicate its meaning. Th=
at's not all or even most MRV cases.<br><br>`map::insert` is a good exa=
mple, because `pair<iterator, bool>` is really impenetrable as to its=
meaning. The `iterator`, you can figure out what that probably means. But =
the `bool` is completely meaningless; you have to look up the documentation=
to know what it means.<br><br>So in a better designed system, this would b=
e a struct with two members. You say that the name of such a struct "i=
s not meaningful". I contest this. A decent name for such a struct wou=
ld be "insertion_state". That's what it is and that's wha=
t it is used for: telling you the state of the system after insertion. That=
name is meaningful.<br><br>I don't think whether the name is meaningfu=
l is a good litmus test for your case. I think a better one is this: what i=
s the likelihood that a user will want to keep that aggregate around <i>as =
an aggregate</i>. That is, would a user be willing to pass it around to oth=
er functions? Not just as pass-through return values, but as a parameter to=
some other function. Will the user store it in some type for longer-durati=
on keeping?<br><br>It is in this case where `insertion_state` has dubious m=
erit. Because... well, I can't see a real reason why I would write a fu=
nction that takes it as a parameter. The two fields basically have nothing =
to do with one another. Nor could I see a reason to store one in a larger d=
ata structure. The `iterator`, I could understand keeping around. But the `=
bool` has value only to the immediate caller of the insertion operation. Th=
e farther you are from that operation, the less likely you will care whethe=
r it actually inserted the object or not.<br><br>So what we're talking =
about is an aggregation who's nature is ephemeral, of the moment. It=
9;s not that the aggregation's name is meaningless; it's that the a=
ggregation <i>itself</i> is meaningless. That the aggregation exists solely=
as a workaround to the lack of MRV support in the language.<br><br>But the=
n, that comes back to my two points. For this to matter, you have to have a=
meaningless aggregation and types which don't explain what they mean. =
After all, the only reason you want to name the return value at all is beca=
use the `bool` argument is unclear as to its meaning. If it were instead:<b=
r><br><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 2=
50); border-color: rgb(187, 187, 187); border-style: solid; border-width: 1=
px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subpr=
ettyprint"><span style=3D"color: #008;" class=3D"styled-by-prettify">enum</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><spa=
n style=3D"color: #008;" class=3D"styled-by-prettify">class</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> did_insert </span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">:</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #00=
8;" class=3D"styled-by-prettify">unsigned</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">char</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"><br></span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"><br>=C2=A0 no_insert </span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettify">0<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 inserted<=
/span><span style=3D"color: #660;" 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>pair</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">,</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> did_insert</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">></span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> insert</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">(...);</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify"><br></span></div></code></div><br>Then the tuple/pair would b=
e perfectly fine. Both values make it clear what they mean simply from thei=
r types. So there is no need to name them.<br><br>So, here's what I wou=
ld like to see. Give me a case where the aggregation is clearly ephemeral, =
yet the meaning of the individual values cannot be inferred from the nature=
of the function and the typenames of those values. `map::insert` is proble=
matic only because it use `bool`; if it had used a more expressive typename=
, it would have been fine.<br><br>I imagine such cases would be limited to =
things like a version stoi that returned multiple values instead of an opti=
onal output parameter. The aggregation is clearly ephemeral, but the return=
values are just basic integer types, without obvious meaning. It seems to =
me that this problem primarily occurs when the return types are basic types=
, which have no inherent meaning provided by the function.<br><br>This is a=
place where weak aliases (a distinct type from the original, but implicitl=
y convertible to/from) could be of value. So stoi could look like:<br><br><=
div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); bo=
rder-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; wor=
d-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettypri=
nt"><span style=3D"color: #008;" class=3D"styled-by-prettify">using</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"> pos_offset </span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</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;" cl=
ass=3D"styled-by-prettify">//Weak alias of `size_t`.</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br><br>pair</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: #000;" class=
=3D"styled-by-prettify"> pos_offset</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">></span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> stoi</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify">string_span str</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">int</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span s=
tyle=3D"color: #008;" class=3D"styled-by-prettify">base</span><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"> </span><span style=3D"color: #066;" class=
=3D"styled-by-prettify">10</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">);</span></div></code></div><br>This gives us clear semanti=
c meaning. The second value is a position offset, so the first value, by pr=
ocess of elimination, must be the converted integer.<br><br>So it seems to =
me that in these cases, better aliasing support could get allow us to get p=
ast these issues. We wouldn't need named return values so much if the t=
ypes had more meaning.<br><br></div><blockquote class=3D"gmail_quote" style=
=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: =
1ex;"><div bgcolor=3D"#FFFFFF" text=3D"#000000">
=20
Think of it as if we had a single parameter with all the input
values of a function call. Giving a name would be most of the time
not meaningful.=C2=A0 We just have instead several parameters.<br></div=
></blockquote><div><br>And if multiple return values were anywhere near as =
common as multiple parameters, your argument might have some weight.<br></d=
iv><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;=
border-left: 1px #ccc solid;padding-left: 1ex;"><div bgcolor=3D"#FFFFFF" te=
xt=3D"#000000">
<blockquote type=3D"cite">
Just consider the main confounding problem of this proposal:<br>
<br>
<div 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>
<div><span style=3D"color:#008">struct</span><span style=3D"color=
:#000"> </span><span style=3D"color:#660">{</span><span style=3D"color:#008=
">int</span><span style=3D"color:#000"> x</span><span style=3D"color:#660">=
;</span><span style=3D"color:#000"> </span><span style=3D"color:#008">float=
</span><span style=3D"color:#000"> y</span><span style=3D"color:#660">}</sp=
an><span style=3D"color:#000">
other_func</span><span style=3D"color:#660">()</span><span st=
yle=3D"color:#000"> </span><span style=3D"color:#660">{...}</span><span sty=
le=3D"color:#000"><br>
</span><span style=3D"color:#008">struct</span><span style=3D"c=
olor:#000"> </span><span style=3D"color:#660">{</span><span style=3D"color:=
#008">int</span><span style=3D"color:#000"> x</span><span style=3D"color:#6=
60">;</span><span style=3D"color:#000"> </span><span style=3D"color:#008">f=
loat</span><span style=3D"color:#000"> y</span><span style=3D"color:#660">}=
</span><span style=3D"color:#000"> func</span><span style=3D"color:#660">()=
</span><span style=3D"color:#000"> </span><span style=3D"color:#660">{</spa=
n><span style=3D"color:#008">return</span><span style=3D"color:#000">
other_func</span><span style=3D"color:#660">();}</span></div>
</code></div>
<br>
Even if we found a way to make this work, I don't really want to =
<i>see
it</i>. When I look at this code, I see repetition; I see the
same type being written twice. I see someone who has not created a
named type who clearly <i>ought to</i>.<br>
</blockquote>
Do you prefer to name it ResultType_for_func_and_other_<wbr>func?</div>=
</blockquote><div><br>Obvious strawman arguments aren't helping your ca=
se.</div><blockquote style=3D"margin: 0px 0px 0px 0.8ex; border-left: 1px s=
olid rgb(204, 204, 204); padding-left: 1ex;" class=3D"gmail_quote"><div></d=
iv></blockquote><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin=
-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div bgcolor=
=3D"#FFFFFF" text=3D"#000000">
=20
<blockquote type=3D"cite">
After all, what is the point of assigning names to the members of
the return value? It's so that the receiver of the object knows
what those values mean. So that we don't have the `<a>map::insert=
</a>`
idiocy where "ret.second" is what tells you whether the obj=
ect was
correctly inserted.<br>
</blockquote>
unnamed struct give exactly that.<br></div></blockquote><div><br>So wou=
ld a <i>named</i> struct, which requires zero language changes.<br></div><b=
lockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;borde=
r-left: 1px #ccc solid;padding-left: 1ex;"><div bgcolor=3D"#FFFFFF" text=3D=
"#000000">
<blockquote type=3D"cite">
If so... you need a struct. A <i>named</i> struct. `std::map`
proves that, since it has several interface functions that all
return the same `pair<iterator, bool>`, and all of them have
the same meaning (the bool tells whether insertion happened, the
iterator says where the element is). If two types have the same
functionality and meaning, they are the same type.<br>
</blockquote>
Waiting for your proposal to change this ;-)<br></div></blockquote><div=
><br>To change what?<br></div><blockquote class=3D"gmail_quote" style=3D"ma=
rgin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">=
<div bgcolor=3D"#FFFFFF" text=3D"#000000">
<blockquote type=3D"cite">How often do you encounter both #1 and #2? Is=
this
often enough to justify such a language feature? With structured
binding making tuples far more usable for MRV than they have ever
been, I just can't understand why we need unnamed struct returns
like this.<br>
</blockquote>
Take in account that a lot of the current code is written using
references as output parameters. Things are changing since move
semantics, RTO, ...<br></div></blockquote><div><br>... I don't real=
ly know what you're getting at with this statement.<br>=C2=A0</div><blo=
ckquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-=
left: 1px #ccc solid;padding-left: 1ex;"><div bgcolor=3D"#FFFFFF" text=3D"#=
000000">
=20
I will replay to you with another questions.<br>
<br>
How many times do you find 1) is useful?<br>
=C2=A0=C2=A0=C2=A0 I have not found a single one at the user level.<br>
<br>
How many times do you have a function that has more than one output
parameters (result)?<br>
=C2=A0=C2=A0=C2=A0 Much more than we used to have.<br></div></blockquot=
e><div><br>For me? Not very often. Indeed, almost never. Maybe my C++ exper=
ience causes me to subconsciously design <i>around</i> the limitations of s=
ingle return values, but I have rarely written functions where I have felt =
a genuine need to return multiple things. Perhaps if I had a functional pro=
gramming background, I'd use them more frequently. But for me, MRV is n=
ot particularly common.<br><br>My experience with Lua, which has native (an=
d very cool) support for multiple return values, bears this out. In that la=
nguage, I have used MRVs more frequently than tuple return values in C++. B=
ut at the same time, I have pretty much never wanted to name <i>individual =
return values</i>. In virtually every case, what the multiple values meant =
was readily apparent; there was no need to give each one a semantic name.<b=
r><br>And if there was a need, then I returned a Lua table with named field=
s. Now, this is where the analogy breaks down, because Lua doesn't have=
static types. But I wouldn't have had any problem giving those aggrega=
tions of values a name.<br><br>You say that you use MRVs more frequently th=
an you used to. Why? What is your code doing that needs to throw around mul=
tiple values like this? It is not clear to me what has changed that causes =
you to code like this.<br><br></div><blockquote class=3D"gmail_quote" style=
=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: =
1ex;"><div bgcolor=3D"#FFFFFF" text=3D"#000000">
=20
So, if the question you are raising is if it is worth doing
something so that we can solve this multiple-value return, <br>
I believe the the answer of the standard committee is yes, otherwise
we will not have tagged tuples, structural bindings, ...<br></div></blo=
ckquote><div><br>Structured bindings and tagged tuples are two completely d=
ifferent things. Structured binding doesn't even have to do with naming=
return values, since it's the <i>receiver</i> who is giving it a meani=
ngful name. A name that notably could be <i>wrong</i>. Indeed, if you call =
a function that returns named MRVs, you <i>shouldn't use</i> structured=
bindings on the return value (most of the time). You'd just use the ag=
gregation directly, accessing the member fields using the convenient names.=
<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-l=
eft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div bgcolor=3D"=
#FFFFFF" text=3D"#000000">
=20
P.S. Note that I'm not against giving a name to an aggregation when
the aggregation has more meaning than just its parts.<br></div></blockq=
uote><div><br>As a general courtesy to my users, if I have to return a `pai=
r` or `tuple` for MRVs, I wrap it in a typedef, so they don't have to t=
ype the whole thing themselves. I give names to meaningless, ephemeral aggr=
egations all the time.<br></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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"https://groups.google.com/a/isocpp.org/group=
/std-proposals/">https://groups.google.com/a/isocpp.org/group/std-proposals=
/</a>.<br />
------=_Part_6027_1431846074.1451841141199--
------=_Part_6026_1424375795.1451841141189--
.
Author: "Vicente J. Botet Escriba" <vicente.botet@wanadoo.fr>
Date: Sun, 3 Jan 2016 21:27:21 +0100
Raw View
This is a multi-part message in MIME format.
--------------040108040304090804000609
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: quoted-printable
Le 03/01/2016 18:12, Nicol Bolas a =C3=A9crit :
> On Sunday, January 3, 2016 at 5:35:33 AM UTC-5, Vicente J. Botet=20
> Escriba wrote:
>
> Le 03/01/2016 04:07, Nicol Bolas a =C3=A9crit :
>> On Wednesday, December 30, 2015 at 8:20:35 AM UTC-5, Vicente J.
>> Botet Escriba wrote:
>>
>> Hi,
>>
>> n4560 introduce the classes tagged, tagged_pair and
>> tagged_tuple. Here follows the rationale as described in n4560:
>>
>> /[Editor=E2=80=99s note: This type exists so that the algorithms=
can
>> return pair- and tuple-like objects with named accessors, as
>> requested by LEWG. Rather than create a bunch of one-off
>> class types with no relation to pair and tuple, I opted
>> instead to create a general utility. I=E2=80=99ll note that this
>> functionality can be merged into pair and tuple directly with
>> minimal breakage, but I opted for now to keep it separate.]//
>> /
>>
>> I was wondering if
>>
>> tagged_pair<tag::in(I), tag::fun(Fun)>
>>
>> couldn't be better be represented by the unnamed aggregate
>>
>> struct {
>> I in;
>> Fun fun;
>> }
>>
>> which has less noise.
>>
>>
>> Here's a question.
>>
>> From my perspective, the principle reason to use a tuple is
>> /metaprogramming/. That is, you're assembling an aggregation of
>> values from some some user-provided construct. A tagged tuple has
>> limited metaprogramming value, but it still has some value in
>> that regard. By tagging types with names, you can develop
>> interfaces between the sender and the receiver of a tuple that
>> allow you to more effectively communicate. Rather than
>> communicating by type or index, you communicate by a name, thus
>> giving the sending code the freedom to pick and choose where the
>> element is in the tuple.
>>
>> That's the reason why we need tagged tuples, and the above case
>> won't even touch that one. Reflection-based aggregate creation
>> might fix it, but that's for C++20, if even that.
>>
>> Using a tuple for plain-old multiple-return-values has always
>> been, to me, of somewhat dubious merit. It's not a terrible, and
>> it's a solution that'll be far more acceptable with structured
>> binding. But using a /tagged/ tuple as a return value from a
>> concrete function? No; that makes no sense.
>>
>> Clearly you should be returning a struct. But that's where I
>> don't get the point of this proposal. Because, well, why does it
>> /have to be/ "unnamed"? I mean, are names /that precious/ that we
>> need to have specialized syntax to do this? Is this:
>>
>> |
>> struct{intx;floaty}func(){...}
>> |
>>
>> Really that much better than this?
>>
>> |
>> structMeaningfulName{intx;floaty};
>>
>> MeaningfulNamefunc(){...}
>> |
>>
>> If the type returned by this function needs to name the
>> individual multiple values, then that aggregation of values
>> probably has some meaning. 9 times out of 10, other functions
>> will want to return that same type. So you're going to need a
>> named type.
> Here is the problem of naming the result type. When we talk of
> returning several values is because we don't have yet one type to
> aggregate them. Most of the time a name is is not meaningful.
>
>
> See, that right there is what I do not believe. It has not been my=20
> experience that the name of such an aggregation "is not meaningful".
>
> Remember, we're not talking about a throwaway MRV case where you would=20
> use a tuple nowadays. We're talking about an MRV case where the=20
> individual return values /need/ a semantic name, where the mere type=20
> or position of the value does not indicate its meaning. That's not all=20
> or even most MRV cases.
No. I'm talking also of those cases, as I don't see a case where the=20
position is enough to transport the semantics. DO you have an example of=20
those cases where pair or tuple would be superior?
>
> `map::insert` is a good example, because `pair<iterator, bool>` is=20
> really impenetrable as to its meaning. The `iterator`, you can figure=20
> out what that probably means. But the `bool` is completely=20
> meaningless; you have to look up the documentation to know what it means.
Yes, these are the common cases that merit a MRV with names.
>
> So in a better designed system, this would be a struct with two=20
> members. You say that the name of such a struct "is not meaningful". I=20
> contest this. A decent name for such a struct would be=20
> "insertion_state". That's what it is and that's what it is used for:=20
> telling you the state of the system after insertion. That name is=20
> meaningful.
I could buy this one. But I would prefer status_and_value<bool,=20
Iterator>. We will need to discus it and find a consensus. You see,=20
naming takes time. I believe this time must be spent when the type has=20
interest on its own, not just because there is a function that returns=20
these two values.
>
> I don't think whether the name is meaningful is a good litmus test for=20
> your case. I think a better one is this: what is the likelihood that a=20
> user will want to keep that aggregate around /as an aggregate/. That=20
> is, would a user be willing to pass it around to other functions? Not=20
> just as pass-through return values, but as a parameter to some other=20
> function. Will the user store it in some type for longer-duration keeping=
?
>
> It is in this case where `insertion_state` has dubious merit.=20
> Because... well, I can't see a real reason why I would write a=20
> function that takes it as a parameter. The two fields basically have=20
> nothing to do with one another.
Agreed.
> Nor could I see a reason to store one in a larger data structure. The=20
> `iterator`, I could understand keeping around. But the `bool` has=20
> value only to the immediate caller of the insertion operation. The=20
> farther you are from that operation, the less likely you will care=20
> whether it actually inserted the object or not.
>
> So what we're talking about is an aggregation who's nature is=20
> ephemeral, of the moment. It's not that the aggregation's name is=20
> meaningless; it's that the aggregation /itself/ is meaningless.
This is the same for me.
> That the aggregation exists solely as a workaround to the lack of MRV=20
> support in the language.
Exactly ;-)
>
> But then, that comes back to my two points. For this to matter, you=20
> have to have a meaningless aggregation and types which don't explain=20
> what they mean. After all, the only reason you want to name the return=20
> value at all is because the `bool` argument is unclear as to its=20
> meaning. If it were instead:
>
> |
> enumclassdid_insert :unsignedchar
> {
> no_insert =3D0,
> inserted,
> };
>
> pair<iterator,did_insert>insert(...);
> |
>
> Then the tuple/pair would be perfectly fine. Both values make it clear=20
> what they mean simply from their types. So there is no need to name them.
Ugh, and access with first and second :( Or are you suggesting the use=20
of get<Iterator>(res) and get<did_insert>(res)?
>
> So, here's what I would like to see. Give me a case where the=20
> aggregation is clearly ephemeral, yet the meaning of the individual=20
> values cannot be inferred from the nature of the function and the=20
> typenames of those values.
A function returning twice the same type ?
> `map::insert` is problematic only because it use `bool`; if it had=20
> used a more expressive typename, it would have been fine.
Not for me, but I can understand that you find it fine.
>
> I imagine such cases would be limited to things like a version stoi=20
> that returned multiple values instead of an optional output parameter.=20
> The aggregation is clearly ephemeral, but the return values are just=20
> basic integer types, without obvious meaning. It seems to me that this=20
> problem primarily occurs when the return types are basic types, which=20
> have no inherent meaning provided by the function.
>
> This is a place where weak aliases (a distinct type from the original,=20
> but implicitly convertible to/from) could be of value. So stoi could=20
> look like:
>
> |
> usingpos_offset =3D...//Weak alias of `size_t`.
>
> pair<int,pos_offset>stoi(string_span str,intbase=3D10);
> |
>
> This gives us clear semantic meaning. The second value is a position=20
> offset, so the first value, by process of elimination, must be the=20
> converted integer.
and when you see in the code res.second it is evident to you that this=20
mean the pos_offset, eh?
>
> So it seems to me that in these cases, better aliasing support could=20
> get allow us to get past these issues. We wouldn't need named return=20
> values so much if the types had more meaning.
I don't agree. The types can be the same and we need something else that=20
gives the semantic.
>
> Think of it as if we had a single parameter with all the input
> values of a function call. Giving a name would be most of the time
> not meaningful. We just have instead several parameters.
>
>
> And if multiple return values were anywhere near as common as multiple=20
> parameters, your argument might have some weight.
>
>> Just consider the main confounding problem of this proposal:
>>
>> |
>> struct{intx;floaty}other_func(){...}
>> struct{intx;floaty}func(){returnother_func();}
>> |
>>
>> Even if we found a way to make this work, I don't really want to
>> /see it/. When I look at this code, I see repetition; I see the
>> same type being written twice. I see someone who has not created
>> a named type who clearly /ought to/.
> Do you prefer to name it ResultType_for_func_and_other_func?
>
>
> Obvious strawman arguments aren't helping your case.
>
>> After all, what is the point of assigning names to the members of
>> the return value? It's so that the receiver of the object knows
>> what those values mean. So that we don't have the `map::insert`
>> idiocy where "ret.second" is what tells you whether the object
>> was correctly inserted.
> unnamed struct give exactly that.
>
>
> So would a /named/ struct, which requires zero language changes.
Independently of the language change this could mean. Would you use=20
unnamedstruct if they were on the language or would you create a=20
specific named struct?
>
>> If so... you need a struct. A /named/ struct. `std::map` proves
>> that, since it has several interface functions that all return
>> the same `pair<iterator, bool>`, and all of them have the same
>> meaning (the bool tells whether insertion happened, the iterator
>> says where the element is). If two types have the same
>> functionality and meaning, they are the same type.
> Waiting for your proposal to change this ;-)
>
>
> To change what?
A change on the standard library, of course.
>
>> How often do you encounter both #1 and #2? Is this often enough
>> to justify such a language feature? With structured binding
>> making tuples far more usable for MRV than they have ever been, I
>> just can't understand why we need unnamed struct returns like this.
> Take in account that a lot of the current code is written using
> references as output parameters. Things are changing since move
> semantics, RTO, ...
>
>
> ... I don't really know what you're getting at with this statement.
I want to signal that I would expect that there will be more a more MRV=20
functions in the future, and that it is worth providing a simple and=20
clear interface for them.
>
> I will replay to you with another questions.
>
> How many times do you find 1) is useful?
> I have not found a single one at the user level.
>
> How many times do you have a function that has more than one
> output parameters (result)?
> Much more than we used to have.
>
>
> For me? Not very often. Indeed, almost never. Maybe my C++ experience=20
> causes me to subconsciously design /around/ the limitations of single=20
> return values, but I have rarely written functions where I have felt a=20
> genuine need to return multiple things. Perhaps if I had a functional=20
> programming background, I'd use them more frequently. But for me, MRV=20
> is not particularly common.
How many time do you then return an aggregate by value?
>
> My experience with Lua, which has native (and very cool) support for=20
> multiple return values, bears this out. In that language, I have used=20
> MRVs more frequently than tuple return values in C++. But at the same=20
> time, I have pretty much never wanted to name /individual return=20
> values/. In virtually every case, what the multiple values meant was=20
> readily apparent; there was no need to give each one a semantic name.
>
> And if there was a need, then I returned a Lua table with named=20
> fields. Now, this is where the analogy breaks down, because Lua=20
> doesn't have static types. But I wouldn't have had any problem giving=20
> those aggregations of values a name.
>
> You say that you use MRVs more frequently than you used to. Why? What=20
> is your code doing that needs to throw around multiple values like=20
> this? It is not clear to me what has changed that causes you to code=20
> like this.
Move semantic, RVO.
>
> So, if the question you are raising is if it is worth doing
> something so that we can solve this multiple-value return,
> I believe the the answer of the standard committee is yes,
> otherwise we will not have tagged tuples, structural bindings, ...
>
>
> Structured bindings and tagged tuples are two completely different=20
> things.
Someone said that they are the same?
> Structured binding doesn't even have to do with naming return values,=20
> since it's the /receiver/ who is giving it a meaningful name.
It has to be with MRV. Pattern matching is another way to access these=20
values and Structural binding is just a particular case.
> A name that notably could be /wrong/.
You can always use the bad name, even with named fields. As you can use=20
..first instead of .second :(
> Indeed, if you call a function that returns named MRVs, you /shouldn't=20
> use/ structured bindings on the return value (most of the time).
We are on a C++ standard proposals ML. What each one should do or not do=20
is not important here.
> You'd just use the aggregation directly, accessing the member fields=20
> using the convenient names.
Let see how do people use them when available.
>
> P.S. Note that I'm not against giving a name to an aggregation
> when the aggregation has more meaning than just its parts.
>
>
> As a general courtesy to my users, if I have to return a `pair` or=20
> `tuple` for MRVs, I wrap it in a typedef, so they don't have to type=20
> the whole thing themselves. I give names to meaningless, ephemeral=20
> aggregations all the time.
>
Naming the type will not prevent to make use .first/.second for pair or=20
the even less friendly get<0>, get<T> for tuple. Again, anything not=20
related to the satndard is out of the scope of this ML. Maybe GSL.
Vicente
--=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 https://groups.google.com/a/isocpp.org/group/std-propos=
als/.
--------------040108040304090804000609
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta content=3D"text/html; charset=3Dutf-8" http-equiv=3D"Content-Type=
">
</head>
<body bgcolor=3D"#FFFFFF" text=3D"#000000">
<div class=3D"moz-cite-prefix">Le 03/01/2016 18:12, Nicol Bolas a
=C3=A9crit=C2=A0:<br>
</div>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">On Sunday, January 3, 2016 at 5:35:33 AM UTC-5,
Vicente J. Botet Escriba wrote:
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<div bgcolor=3D"#FFFFFF" text=3D"#000000">
<div>Le 03/01/2016 04:07, Nicol Bolas a =C3=A9crit=C2=A0:<br>
</div>
<blockquote type=3D"cite">On Wednesday, December 30, 2015 at
8:20:35 AM UTC-5, Vicente J. Botet Escriba wrote:
<blockquote class=3D"gmail_quote"
style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc
solid;padding-left:1ex">
<div bgcolor=3D"#FFFFFF" text=3D"#000000"> Hi,<br>
<br>
n4560 introduce the classes tagged, tagged_pair and
tagged_tuple. Here follows the rationale as described in
n4560:<br>
<br>
<i>[Editor=E2=80=99s note: This type exists so that the
algorithms can return pair- and tuple-like objects
with named accessors, as requested by LEWG. Rather
than create a bunch of one-off class types with no
relation to pair and tuple, I opted instead to create
a general utility. I=E2=80=99ll note that this functional=
ity
can be merged into pair and tuple directly with
minimal breakage, but I opted for now to keep it
separate.]</i><i><br>
</i><br>
<br>
I was wondering if<br>
<br>
=C2=A0=C2=A0=C2=A0 tagged_pair<tag::in(I), tag::fun(Fun)=
><br>
<br>
couldn't be better be represented by the unnamed
aggregate<br>
<br>
=C2=A0=C2=A0=C2=A0 struct {<br>
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 I in;<br>
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 Fun fun;<br>
=C2=A0=C2=A0=C2=A0 }<br>
<br>
which has less noise.<br>
</div>
</blockquote>
<br>
Here's a question.<br>
<br>
From my perspective, the principle reason to use a tuple is
<i>metaprogramming</i>. That is, you're assembling an
aggregation of values from some some user-provided
construct. A tagged tuple has limited metaprogramming value,
but it still has some value in that regard. By tagging types
with names, you can develop interfaces between the sender
and the receiver of a tuple that allow you to more
effectively communicate. Rather than communicating by type
or index, you communicate by a name, thus giving the sending
code the freedom to pick and choose where the element is in
the tuple.<br>
<br>
That's the reason why we need tagged tuples, and the above
case won't even touch that one. Reflection-based aggregate
creation might fix it, but that's for C++20, if even that.<br>
<br>
Using a tuple for plain-old multiple-return-values has
always been, to me, of somewhat dubious merit. It's not a
terrible, and it's a solution that'll be far more acceptable
with structured binding. But using a <i>tagged</i> tuple as
a return value from a concrete function? No; that makes no
sense.<br>
<br>
Clearly you should be returning a struct. But that's where I
don't get the point of this proposal. Because, well, why
does it <i>have to be</i> "unnamed"? I mean, are names <i>that
precious</i> that we need to have specialized syntax to do
this? Is this:<br>
<br>
<div
style=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);bo=
rder-style:solid;border-width:1px;word-wrap:break-word"><code>
<div><span style=3D"color:#008">struct</span><span
style=3D"color:#000"> </span><span style=3D"color:#660"=
>{</span><span
style=3D"color:#008">int</span><span
style=3D"color:#000"> x</span><span style=3D"color:#660=
">;</span><span
style=3D"color:#000"> </span><span style=3D"color:#008"=
>float</span><span
style=3D"color:#000"> y</span><span style=3D"color:#660=
">}</span><span
style=3D"color:#000"> func</span><span
style=3D"color:#660">()</span><span style=3D"color:#000=
">
</span><span style=3D"color:#660">{...}</span></div>
</code></div>
<br>
Really that much better than this?<br>
<br>
<div
style=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);bo=
rder-style:solid;border-width:1px;word-wrap:break-word"><code>
<div><span style=3D"color:#008">struct</span><span
style=3D"color:#000"> </span><span style=3D"color:#606"=
>MeaningfulName</span><span
style=3D"color:#000"> </span><span style=3D"color:#660"=
>{</span><span
style=3D"color:#008">int</span><span
style=3D"color:#000"> x</span><span style=3D"color:#660=
">;</span><span
style=3D"color:#000"> </span><span style=3D"color:#008"=
>float</span><span
style=3D"color:#000"> y</span><span style=3D"color:#660=
">};</span><span
style=3D"color:#000"><br>
<br>
</span><span style=3D"color:#606">MeaningfulName</span><s=
pan
style=3D"color:#000"> func</span><span
style=3D"color:#660">()</span><span style=3D"color:#000=
">
</span><span style=3D"color:#660">{...}</span></div>
</code></div>
<br>
If the type returned by this function needs to name the
individual multiple values, then that aggregation of values
probably has some meaning. 9 times out of 10, other
functions will want to return that same type. So you're
going to need a named type.<br>
</blockquote>
Here is the problem of naming the result type. When we talk of
returning several values is because we don't have yet one type
to aggregate them. Most of the time a name is is not
meaningful.<br>
</div>
</blockquote>
<div><br>
See, that right there is what I do not believe. It has not been
my experience that the name of such an aggregation "is not
meaningful".<br>
<br>
Remember, we're not talking about a throwaway MRV case where you
would use a tuple nowadays. We're talking about an MRV case
where the individual return values <i>need</i> a semantic name,
where the mere type or position of the value does not indicate
its meaning. That's not all or even most MRV cases.<br>
</div>
</blockquote>
No. I'm talking also of those cases, as I don't see a case where the
position is enough to transport the semantics. DO you have an
example of those cases where pair or tuple would be superior?<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<div><br>
`<a class=3D"moz-txt-link-freetext" href=3D"map::insert">map::inser=
t</a>` is a good example, because `pair<iterator,
bool>` is really impenetrable as to its meaning. The
`iterator`, you can figure out what that probably means. But the
`bool` is completely meaningless; you have to look up the
documentation to know what it means.<br>
</div>
</blockquote>
Yes, these are the common cases that merit a MRV with names.<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<div><br>
So in a better designed system, this would be a struct with two
members. You say that the name of such a struct "is not
meaningful". I contest this. A decent name for such a struct
would be "insertion_state". That's what it is and that's what it
is used for: telling you the state of the system after
insertion. That name is meaningful.<br>
</div>
</blockquote>
I could buy this one. But I would prefer status_and_value<bool,
Iterator>. We will need to discus it and find a consensus. You
see, naming takes time. I believe this time must be spent when the
type has interest on its own, not just because there is a function
that returns these two values.<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<div><br>
I don't think whether the name is meaningful is a good litmus
test for your case. I think a better one is this: what is the
likelihood that a user will want to keep that aggregate around <i>a=
s
an aggregate</i>. That is, would a user be willing to pass it
around to other functions? Not just as pass-through return
values, but as a parameter to some other function. Will the user
store it in some type for longer-duration keeping?<br>
<br>
It is in this case where `insertion_state` has dubious merit.
Because... well, I can't see a real reason why I would write a
function that takes it as a parameter. The two fields basically
have nothing to do with one another. </div>
</blockquote>
Agreed.<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<div>Nor could I see a reason to store one in a larger data
structure. The `iterator`, I could understand keeping around.
But the `bool` has value only to the immediate caller of the
insertion operation. The farther you are from that operation,
the less likely you will care whether it actually inserted the
object or not.<br>
<br>
So what we're talking about is an aggregation who's nature is
ephemeral, of the moment. It's not that the aggregation's name
is meaningless; it's that the aggregation <i>itself</i> is
meaningless. </div>
</blockquote>
This is the same for me.<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<div>That the aggregation exists solely as a workaround to the
lack of MRV support in the language.<br>
</div>
</blockquote>
Exactly ;-)<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<div><br>
But then, that comes back to my two points. For this to matter,
you have to have a meaningless aggregation and types which don't
explain what they mean. After all, the only reason you want to
name the return value at all is because the `bool` argument is
unclear as to its meaning. If it were instead:<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-prettify">enum</span><span
style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span
style=3D"color: #008;" class=3D"styled-by-prettify">class</=
span><span
style=3D"color: #000;" class=3D"styled-by-prettify">
did_insert </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">unsigne=
d</span><span
style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span
style=3D"color: #008;" class=3D"styled-by-prettify">char</s=
pan><span
style=3D"color: #000;" class=3D"styled-by-prettify"><br>
</span><span style=3D"color: #660;"
class=3D"styled-by-prettify">{</span><span style=3D"color:
#000;" class=3D"styled-by-prettify"><br>
=C2=A0 no_insert </span><span style=3D"color: #660;"
class=3D"styled-by-prettify">=3D</span><span style=3D"color=
:
#000;" class=3D"styled-by-prettify"> </span><span
style=3D"color: #066;" class=3D"styled-by-prettify">0</span=
><span
style=3D"color: #660;" class=3D"styled-by-prettify">,</span=
><span
style=3D"color: #000;" class=3D"styled-by-prettify"><br>
=C2=A0 inserted</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: #660;"
class=3D"styled-by-prettify">};</span><span style=3D"color:
#000;" class=3D"styled-by-prettify"><br>
<br>
pair</span><span style=3D"color: #660;"
class=3D"styled-by-prettify"><</span><span
style=3D"color: #000;" class=3D"styled-by-prettify">iterato=
r</span><span
style=3D"color: #660;" class=3D"styled-by-prettify">,</span=
><span
style=3D"color: #000;" class=3D"styled-by-prettify">
did_insert</span><span style=3D"color: #660;"
class=3D"styled-by-prettify">></span><span
style=3D"color: #000;" class=3D"styled-by-prettify"> insert=
</span><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>
Then the tuple/pair would be perfectly fine. Both values make it
clear what they mean simply from their types. So there is no
need to name them.<br>
</div>
</blockquote>
Ugh, and access with first and second :( Or are you suggesting the
use of get<Iterator>(res) and get<did_insert>(res)?<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<div><br>
So, here's what I would like to see. Give me a case where the
aggregation is clearly ephemeral, yet the meaning of the
individual values cannot be inferred from the nature of the
function and the typenames of those values. </div>
</blockquote>
A function returning twice the same type ?<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<div>`<a class=3D"moz-txt-link-freetext" href=3D"map::insert">map::in=
sert</a>` is problematic only because it use `bool`; if
it had used a more expressive typename, it would have been fine.<br=
>
</div>
</blockquote>
Not for me, but I can understand that you find it fine.<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<div><br>
I imagine such cases would be limited to things like a version
stoi that returned multiple values instead of an optional output
parameter. The aggregation is clearly ephemeral, but the return
values are just basic integer types, without obvious meaning. It
seems to me that this problem primarily occurs when the return
types are basic types, which have no inherent meaning provided
by the function.<br>
<br>
This is a place where weak aliases (a distinct type from the
original, but implicitly convertible to/from) could be of value.
So stoi could look like:<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-prettify">using</span><span
style=3D"color: #000;" class=3D"styled-by-prettify">
pos_offset </span><span style=3D"color: #660;"
class=3D"styled-by-prettify">=3D</span><span style=3D"color=
:
#000;" class=3D"styled-by-prettify"> </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: #800;" class=3D"styled-by-prettify">//Weak
alias of `size_t`.</span><span style=3D"color: #000;"
class=3D"styled-by-prettify"><br>
<br>
pair</span><span style=3D"color: #660;"
class=3D"styled-by-prettify"><</span><span
style=3D"color: #008;" class=3D"styled-by-prettify">int</sp=
an><span
style=3D"color: #660;" class=3D"styled-by-prettify">,</span=
><span
style=3D"color: #000;" class=3D"styled-by-prettify">
pos_offset</span><span style=3D"color: #660;"
class=3D"styled-by-prettify">></span><span
style=3D"color: #000;" class=3D"styled-by-prettify"> stoi</=
span><span
style=3D"color: #660;" class=3D"styled-by-prettify">(</span=
><span
style=3D"color: #000;" class=3D"styled-by-prettify">string_=
span
str</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">int</sp=
an><span
style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span
style=3D"color: #008;" class=3D"styled-by-prettify">base</s=
pan><span
style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span
style=3D"color: #660;" class=3D"styled-by-prettify">=3D</sp=
an><span
style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span
style=3D"color: #066;" class=3D"styled-by-prettify">10</spa=
n><span
style=3D"color: #660;" class=3D"styled-by-prettify">);</spa=
n></div>
</code></div>
<br>
This gives us clear semantic meaning. The second value is a
position offset, so the first value, by process of elimination,
must be the converted integer.<br>
</div>
</blockquote>
<br>
and when you see in the code res.second it is evident to you that
this mean the pos_offset, eh?<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<div><br>
So it seems to me that in these cases, better aliasing support
could get allow us to get past these issues. We wouldn't need
named return values so much if the types had more meaning.<br>
</div>
</blockquote>
I don't agree. The types can be the same and we need something else
that gives the semantic.<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<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 bgcolor=3D"#FFFFFF" text=3D"#000000"> Think of it as if we had
a single parameter with all the input values of a function
call. Giving a name would be most of the time not meaningful.=C2=
=A0
We just have instead several parameters.<br>
</div>
</blockquote>
<div><br>
And if multiple return values were anywhere near as common as
multiple parameters, your argument might have some weight.<br>
</div>
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<div bgcolor=3D"#FFFFFF" text=3D"#000000">
<blockquote type=3D"cite"> Just consider the main confounding
problem of this proposal:<br>
<br>
<div
style=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);bo=
rder-style:solid;border-width:1px;word-wrap:break-word"><code>
<div><span style=3D"color:#008">struct</span><span
style=3D"color:#000"> </span><span style=3D"color:#660"=
>{</span><span
style=3D"color:#008">int</span><span
style=3D"color:#000"> x</span><span style=3D"color:#660=
">;</span><span
style=3D"color:#000"> </span><span style=3D"color:#008"=
>float</span><span
style=3D"color:#000"> y</span><span style=3D"color:#660=
">}</span><span
style=3D"color:#000"> other_func</span><span
style=3D"color:#660">()</span><span style=3D"color:#000=
">
</span><span style=3D"color:#660">{...}</span><span
style=3D"color:#000"><br>
</span><span style=3D"color:#008">struct</span><span
style=3D"color:#000"> </span><span style=3D"color:#660"=
>{</span><span
style=3D"color:#008">int</span><span
style=3D"color:#000"> x</span><span style=3D"color:#660=
">;</span><span
style=3D"color:#000"> </span><span style=3D"color:#008"=
>float</span><span
style=3D"color:#000"> y</span><span style=3D"color:#660=
">}</span><span
style=3D"color:#000"> func</span><span
style=3D"color:#660">()</span><span style=3D"color:#000=
">
</span><span style=3D"color:#660">{</span><span
style=3D"color:#008">return</span><span
style=3D"color:#000"> other_func</span><span
style=3D"color:#660">();}</span></div>
</code></div>
<br>
Even if we found a way to make this work, I don't really
want to <i>see it</i>. When I look at this code, I see
repetition; I see the same type being written twice. I see
someone who has not created a named type who clearly <i>ought
to</i>.<br>
</blockquote>
Do you prefer to name it ResultType_for_func_and_other_<wbr>func?=
</div>
</blockquote>
<div><br>
Obvious strawman arguments aren't helping your case.</div>
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<div bgcolor=3D"#FFFFFF" text=3D"#000000">
<blockquote type=3D"cite"> After all, what is the point of
assigning names to the members of the return value? It's so
that the receiver of the object knows what those values
mean. So that we don't have the `<a moz-do-not-send=3D"true">ma=
p::insert</a>`
idiocy where "ret.second" is what tells you whether the
object was correctly inserted.<br>
</blockquote>
unnamed struct give exactly that.<br>
</div>
</blockquote>
<div><br>
So would a <i>named</i> struct, which requires zero language
changes.<br>
</div>
</blockquote>
Independently of the language change this could mean. Would you use
unnamedstruct if they were on the language or would you create a
specific named struct?<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<div bgcolor=3D"#FFFFFF" text=3D"#000000">
<blockquote type=3D"cite"> If so... you need a struct. A <i>named=
</i>
struct. `std::map` proves that, since it has several
interface functions that all return the same
`pair<iterator, bool>`, and all of them have the same
meaning (the bool tells whether insertion happened, the
iterator says where the element is). If two types have the
same functionality and meaning, they are the same type.<br>
</blockquote>
Waiting for your proposal to change this ;-)<br>
</div>
</blockquote>
<div><br>
To change what?<br>
</div>
</blockquote>
A change on the standard library, of course.<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<div bgcolor=3D"#FFFFFF" text=3D"#000000">
<blockquote type=3D"cite">How often do you encounter both #1 and
#2? Is this often enough to justify such a language feature?
With structured binding making tuples far more usable for
MRV than they have ever been, I just can't understand why we
need unnamed struct returns like this.<br>
</blockquote>
Take in account that a lot of the current code is written
using references as output parameters. Things are changing
since move semantics, RTO, ...<br>
</div>
</blockquote>
<div><br>
... I don't really know what you're getting at with this
statement.<br>
</div>
</blockquote>
I want to signal that I would expect that there will be more a more
MRV functions in the future, and that it is worth providing a simple
and clear interface for them.<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<div>=C2=A0</div>
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<div bgcolor=3D"#FFFFFF" text=3D"#000000"> I will replay to you wit=
h
another questions.<br>
<br>
How many times do you find 1) is useful?<br>
=C2=A0=C2=A0=C2=A0 I have not found a single one at the user leve=
l.<br>
<br>
How many times do you have a function that has more than one
output parameters (result)?<br>
=C2=A0=C2=A0=C2=A0 Much more than we used to have.<br>
</div>
</blockquote>
<div><br>
For me? Not very often. Indeed, almost never. Maybe my C++
experience causes me to subconsciously design <i>around</i> the
limitations of single return values, but I have rarely written
functions where I have felt a genuine need to return multiple
things. Perhaps if I had a functional programming background,
I'd use them more frequently. But for me, MRV is not
particularly common.<br>
</div>
</blockquote>
How many time do you then return an aggregate by value? <br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<div><br>
My experience with Lua, which has native (and very cool) support
for multiple return values, bears this out. In that language, I
have used MRVs more frequently than tuple return values in C++.
But at the same time, I have pretty much never wanted to name <i>in=
dividual
return values</i>. In virtually every case, what the multiple
values meant was readily apparent; there was no need to give
each one a semantic name.<br>
<br>
And if there was a need, then I returned a Lua table with named
fields. Now, this is where the analogy breaks down, because Lua
doesn't have static types. But I wouldn't have had any problem
giving those aggregations of values a name.<br>
<br>
You say that you use MRVs more frequently than you used to. Why?
What is your code doing that needs to throw around multiple
values like this? It is not clear to me what has changed that
causes you to code like this.<br>
</div>
</blockquote>
Move semantic, RVO.<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<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 bgcolor=3D"#FFFFFF" text=3D"#000000"> So, if the question you
are raising is if it is worth doing something so that we can
solve this multiple-value return, <br>
I believe the the answer of the standard committee is yes,
otherwise we will not have tagged tuples, structural bindings,
...<br>
</div>
</blockquote>
<div><br>
Structured bindings and tagged tuples are two completely
different things. </div>
</blockquote>
Someone said that they are the same?<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<div>Structured binding doesn't even have to do with naming return
values, since it's the <i>receiver</i> who is giving it a
meaningful name.</div>
</blockquote>
It has to be with MRV. Pattern matching is another way to access
these values and Structural binding is just a particular case.<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<div> A name that notably could be <i>wrong</i>. </div>
</blockquote>
You can always use the bad name, even with named fields. As you can
use .first instead of .second :(<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<div>Indeed, if you call a function that returns named MRVs, you <i>s=
houldn't
use</i> structured bindings on the return value (most of the
time). </div>
</blockquote>
We are on a C++ standard proposals ML. What each one should do or
not do is not important here.<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<div>You'd just use the aggregation directly, accessing the member
fields using the convenient names.<br>
</div>
</blockquote>
Let see how do people use them when available.<br>
<blockquote
cite=3D"mid:a3534d92-5e08-4879-99bd-d5e12291538b@isocpp.org"
type=3D"cite">
<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 bgcolor=3D"#FFFFFF" text=3D"#000000"> P.S. Note that I'm not
against giving a name to an aggregation when the aggregation
has more meaning than just its parts.<br>
</div>
</blockquote>
<div><br>
As a general courtesy to my users, if I have to return a `pair`
or `tuple` for MRVs, I wrap it in a typedef, so they don't have
to type the whole thing themselves. I give names to meaningless,
ephemeral aggregations all the time.<br>
</div>
<br>
</blockquote>
Naming the type will not prevent to make use .first/.second for pair
or the even less friendly get<0>, get<T> for tuple.
Again, anything not related to the satndard is out of the scope of
this ML. Maybe GSL.<br>
<br>
Vicente<br>
</body>
</html>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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"https://groups.google.com/a/isocpp.org/group=
/std-proposals/">https://groups.google.com/a/isocpp.org/group/std-proposals=
/</a>.<br />
--------------040108040304090804000609--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Mon, 4 Jan 2016 08:31:24 -0800 (PST)
Raw View
------=_Part_169_1785469245.1451925084407
Content-Type: multipart/alternative;
boundary="----=_Part_170_169413274.1451925084408"
------=_Part_170_169413274.1451925084408
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Sunday, January 3, 2016 at 3:27:25 PM UTC-5, Vicente J. Botet Escriba=20
wrote:
>
> Le 03/01/2016 18:12, Nicol Bolas a =C3=A9crit :
>
> On Sunday, January 3, 2016 at 5:35:33 AM UTC-5, Vicente J. Botet Escriba=
=20
> wrote:=20
>>
>> Le 03/01/2016 04:07, Nicol Bolas a =C3=A9crit :
>>
>> On Wednesday, December 30, 2015 at 8:20:35 AM UTC-5, Vicente J. Botet=20
>> Escriba wrote:=20
>>>
>>> Hi,
>>>
>>> n4560 introduce the classes tagged, tagged_pair and tagged_tuple. Here=
=20
>>> follows the rationale as described in n4560:
>>>
>>> *[Editor=E2=80=99s note: This type exists so that the algorithms can re=
turn=20
>>> pair- and tuple-like objects with named accessors, as requested by LEWG=
..=20
>>> Rather than create a bunch of one-off class types with no relation to p=
air=20
>>> and tuple, I opted instead to create a general utility. I=E2=80=99ll no=
te that this=20
>>> functionality can be merged into pair and tuple directly with minimal=
=20
>>> breakage, but I opted for now to keep it separate.]*
>>>
>>>
>>> I was wondering if
>>>
>>> tagged_pair<tag::in(I), tag::fun(Fun)>
>>>
>>> couldn't be better be represented by the unnamed aggregate
>>>
>>> struct {
>>> I in;
>>> Fun fun;
>>> }
>>>
>>> which has less noise.
>>>
>>
>> Here's a question.
>>
>> From my perspective, the principle reason to use a tuple is=20
>> *metaprogramming*. That is, you're assembling an aggregation of values=
=20
>> from some some user-provided construct. A tagged tuple has limited=20
>> metaprogramming value, but it still has some value in that regard. By=20
>> tagging types with names, you can develop interfaces between the sender =
and=20
>> the receiver of a tuple that allow you to more effectively communicate.=
=20
>> Rather than communicating by type or index, you communicate by a name, t=
hus=20
>> giving the sending code the freedom to pick and choose where the element=
is=20
>> in the tuple.
>>
>> That's the reason why we need tagged tuples, and the above case won't=20
>> even touch that one. Reflection-based aggregate creation might fix it, b=
ut=20
>> that's for C++20, if even that.
>>
>> Using a tuple for plain-old multiple-return-values has always been, to=
=20
>> me, of somewhat dubious merit. It's not a terrible, and it's a solution=
=20
>> that'll be far more acceptable with structured binding. But using a=20
>> *tagged* tuple as a return value from a concrete function? No; that=20
>> makes no sense.
>>
>> Clearly you should be returning a struct. But that's where I don't get=
=20
>> the point of this proposal. Because, well, why does it *have to be*=20
>> "unnamed"? I mean, are names *that precious* that we need to have=20
>> specialized syntax to do this? Is this:
>>
>> struct {int x; float y} func() {...}
>>
>> Really that much better than this?
>>
>> struct MeaningfulName {int x; float y};
>>
>> MeaningfulName func() {...}
>>
>> If the type returned by this function needs to name the individual=20
>> multiple values, then that aggregation of values probably has some meani=
ng.=20
>> 9 times out of 10, other functions will want to return that same type. S=
o=20
>> you're going to need a named type.
>>
>> Here is the problem of naming the result type. When we talk of returning=
=20
>> several values is because we don't have yet one type to aggregate them.=
=20
>> Most of the time a name is is not meaningful.
>>
>
> See, that right there is what I do not believe. It has not been my=20
> experience that the name of such an aggregation "is not meaningful".
>
> Remember, we're not talking about a throwaway MRV case where you would us=
e=20
> a tuple nowadays. We're talking about an MRV case where the individual=20
> return values *need* a semantic name, where the mere type or position of=
=20
> the value does not indicate its meaning. That's not all or even most MRV=
=20
> cases.
>
> No. I'm talking also of those cases, as I don't see a case where the=20
> position is enough to transport the semantics. DO you have an example of=
=20
> those cases where pair or tuple would be superior?
>
How do you define "superior"?
I would say that if the `pair` returned from `map::insert` were=20
`pair<iterator, did_insert>` this would be *sufficient* information for the=
=20
user to figure out what's going on.
Would a `struct{ iterator insert_loc; bool did_insert}` return value be=20
"superior" to that? By some measures, yes. But it would also be *longer*;=
=20
it'd require more reading. Does that make it inferior to the other? Who=20
decides?
"Good enough" is good enough to me. `pair<iterator, did_insert>` is good=20
enough to be clear to the reader what the return value means. So having a=
=20
superior solution is unnecessary, even if we accept that your proposed=20
solution is "superior".
It stops being a "need" and becomes a "maybe nice to have." And we=20
shouldn't make major language changes for a "maybe nice to have."
> So in a better designed system, this would be a struct with two members.=
=20
> You say that the name of such a struct "is not meaningful". I contest thi=
s.=20
> A decent name for such a struct would be "insertion_state". That's what i=
t=20
> is and that's what it is used for: telling you the state of the system=20
> after insertion. That name is meaningful.
>
> I could buy this one. But I would prefer status_and_value<bool, Iterator>=
..=20
> We will need to discus it and find a consensus. You see, naming takes tim=
e.=20
> I believe this time must be spent when the type has interest on its own,=
=20
> not just because there is a function that returns these two values.
>
And exactly how would this be changed by `struct{iterator insert_loc; bool=
=20
did_insert}`? We'd still have to bikeshed about both the name of the=20
individual fields and the *order* of those fields (yours put the "status"=
=20
first). So what if you add one more thing to the pile of bikeshedding?
Most importantly of all... who cares? Any (not-deliberately-stupid) name=20
you pick will be preferable to the impenetrable `pair<iterator, bool>`.=20
Stop caring so much about whether a name is *perfect*. Especially when you=
=20
care to the point where you start arguing that we shouldn't have names at=
=20
all just to prevent bikeshedding. *Just pick one and move on.*
Nothing annoys me quite so much as name bikeshedding. Unless there's a=20
genuine linguistic/syntactic problem, or the name is *provably* ambiguous,=
=20
or there is an explicit and well-defined naming convention that would be=20
violated, just take the first one suggested and move on.
> But then, that comes back to my two points. For this to matter, you have=
=20
> to have a meaningless aggregation and types which don't explain what they=
=20
> mean. After all, the only reason you want to name the return value at all=
=20
> is because the `bool` argument is unclear as to its meaning. If it were=
=20
> instead:
>
> enum class did_insert : unsigned char
> {
> no_insert =3D 0,
> inserted,
> };
>
> pair<iterator, did_insert> insert(...);
>
> Then the tuple/pair would be perfectly fine. Both values make it clear=20
> what they mean simply from their types. So there is no need to name them.
>
> Ugh, and access with first and second :( Or are you suggesting the use of=
=20
> get<Iterator>(res) and get<did_insert>(res)?
>
I don't care what you use to access the values (and I'll care even less=20
with structured binding). What I care about is what the reader of the *func=
tion=20
signature* sees. The user sees that the function returns an `iterator`=20
value and a `did_insert` value. From those type names, coupled with the=20
nature of the function, the user can deduce what the values mean.
And therefore, the function has improved clarity over `pair<iterator, bool>=
=20
insert()`.
> So, here's what I would like to see. Give me a case where the aggregation=
=20
> is clearly ephemeral, yet the meaning of the individual values cannot be=
=20
> inferred from the nature of the function and the typenames of those value=
s.=20
>
> A function returning twice the same type ?
>
OK, *why* is it "returning twice the same type"? I don't want some=20
arbitrary "here's a thing that could happen". I want a concrete function=20
that performs a useful operation where "returning twice the same type" is a=
=20
legitimate operation.
For instance, `stoul/stoull`, if we want to replace the optional parameter=
=20
with a return value. But I already covered that one with a type alias.
Independently of the language change this could mean. Would you use=20
> unnamedstruct if they were on the language or would you create a specific=
=20
> named struct?
>
If it were magically available today across all compilers and had been for=
=20
years (and you reasonably resolve all of the various problems with the=20
idea), sure, I'd probably use it. *Occasionally*. I'm not an "always use=20
auto" zealot, so I prefer not to do things that require users to use `auto`=
=20
(which is why I typedef my `tuple`s). So I would avoid this construct=20
unless there was good reason not to.
But in any case, the question is irrelevant. You're not proposing that we=
=20
go back in time and stick it into C++98. You're proposing it *now*.
Well, we don't *need* it. With better aliasing support on the sender's=20
side, and structured bindings on the receiver's side, the number of cases=
=20
where positional return values would be ambiguous would be few if ever.
So the improvements in legibility or program clarity are minimal over the=
=20
tools we're already going to be getting (hopefully).
> If so... you need a struct. A *named* struct. `std::map` proves that,=20
>> since it has several interface functions that all return the same=20
>> `pair<iterator, bool>`, and all of them have the same meaning (the bool=
=20
>> tells whether insertion happened, the iterator says where the element is=
).=20
>> If two types have the same functionality and meaning, they are the same=
=20
>> type.
>>
>> Waiting for your proposal to change this ;-)
>>
>
> To change what?
>
> A change on the standard library, of course.
>
This small improvement to clarity is not important enough for a breaking=20
change. If we get new versions of containers for any "STL2" type thing,=20
then obviously this should be resolved. But the committee would rightly=20
reject any breaking proposal just to fix this.
> How often do you encounter both #1 and #2? Is this often enough to justif=
y=20
>> such a language feature? With structured binding making tuples far more=
=20
>> usable for MRV than they have ever been, I just can't understand why we=
=20
>> need unnamed struct returns like this.
>>
>> Take in account that a lot of the current code is written using=20
>> references as output parameters. Things are changing since move semantic=
s,=20
>> RTO, ...
>>
>
> ... I don't really know what you're getting at with this statement.
>
> I want to signal that I would expect that there will be more a more MRV=
=20
> functions in the future, and that it is worth providing a simple and clea=
r=20
> interface for them.
>
OK, why do you expect that? Equally importantly, why do you think "a lot of=
=20
the current code is written using references as output parameters"? There=
=20
really aren't that many functions out there which *try* to return multiple=
=20
values, whether via tuples, reference parameters, or whatever.
That's not to say that it doesn't happen. But we are hardly being overrun=
=20
by functions that have MRVs of some form.
> =20
>
>> I will replay to you with another questions.
>>
>> How many times do you find 1) is useful?
>> I have not found a single one at the user level.
>>
>> How many times do you have a function that has more than one output=20
>> parameters (result)?
>> Much more than we used to have.
>>
>
> For me? Not very often. Indeed, almost never. Maybe my C++ experience=20
> causes me to subconsciously design *around* the limitations of single=20
> return values, but I have rarely written functions where I have felt a=20
> genuine need to return multiple things. Perhaps if I had a functional=20
> programming background, I'd use them more frequently. But for me, MRV is=
=20
> not particularly common.
>
> How many time do you then return an aggregate by value?=20
>
.... I don't understand your logic.
On the one hand, you agreed with my notion that named MRVs are about cases=
=20
where "the aggregation *itself* is meaningless". And now you seem to be=20
suggesting that *any* aggregate returned by value is meaningless and ought=
=20
to be an unnamed struct.
Do you not see how those are different?
I return lots of *things* by value. Those "things" might be basic types,=20
classes or simple aggregates. But in all cases, they are *a single,=20
conceptual value*.
If I return a 3D vector struct, I am returning *a 3D vector*. It is a *sing=
le=20
value* that happens to have multiple elements to it. It is not 3 separate=
=20
return values, even if the type is classified as a C++ aggregate.
I return plenty of aggregates by value. And in none of those cases would I=
=20
use an unnamed aggregate, because those aggregations have *meaning*. In=20
virtually every case, there are functions that take them as parameters or=
=20
types that use them.
What often happens to me is that I will start developing with what seems=20
like an MRV. But logical use of that API turns it into a meaningful=20
aggregate. For example, I have an class that represents a set of images. I=
=20
need to get the width, height, possibly depth, etc of the image. At first,=
=20
I considered just a `GetWidth`, `GetHeight`, etc. But then I decided to=20
have a `GetDimensions` function that returns an aggregate of all of them.
At which point... I started using that `Dimensions` type in many places.=20
Instead of having functions that take a width/height, I just pass=20
`Dimensions`. And internally in the ImageSet class, I store a `Dimensions`=
=20
object; it just makes things simpler.
I have rarely had the need to return some aggregation that had no=20
fundamental meaning beyond that function.
> My experience with Lua, which has native (and very cool) support for=20
> multiple return values, bears this out. In that language, I have used MRV=
s=20
> more frequently than tuple return values in C++. But at the same time, I=
=20
> have pretty much never wanted to name *individual return values*. In=20
> virtually every case, what the multiple values meant was readily apparent=
;=20
> there was no need to give each one a semantic name.
>
> And if there was a need, then I returned a Lua table with named fields.=
=20
> Now, this is where the analogy breaks down, because Lua doesn't have stat=
ic=20
> types. But I wouldn't have had any problem giving those aggregations of=
=20
> values a name.
>
> You say that you use MRVs more frequently than you used to. Why? What is=
=20
> your code doing that needs to throw around multiple values like this? It =
is=20
> not clear to me what has changed that causes you to code like this.
>
> Move semantic, RVO.
>
That's not an answer.
In order for MRVs to be more frequent now in your code than they were=20
before, you have to actually be writing functions that return more than one=
=20
conceptual thing to the user. That is, you're not returning a value-struct=
=20
which has some innate meaning; your function is returning two or more=20
conceptual values which have little if any coupling (like `map::insert`).
What kinds of functions are you writing that *require* you to return=20
multiple, uncoupled values?
> Indeed, if you call a function that returns named MRVs, you *shouldn't=20
> use* structured bindings on the return value (most of the time).=20
>
> We are on a C++ standard proposals ML. What each one should do or not do=
=20
> is not important here.
>
.... what?
How a feature ought to be used by people is very important for discussion=
=20
of a proposal. We don't want to add features to the language that make it=
=20
*worse*.
Or have we forgotten the `operator&`/`addressof` debacle?
>
--=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 https://groups.google.com/a/isocpp.org/group/std-propos=
als/.
------=_Part_170_169413274.1451925084408
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Sunday, January 3, 2016 at 3:27:25 PM UTC-5, Vicente J. Botet Escriba wr=
ote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;">
=20
=20
=20
<div bgcolor=3D"#FFFFFF" text=3D"#000000">
<div>Le 03/01/2016 18:12, Nicol Bolas a
=C3=A9crit=C2=A0:<br>
</div>
<blockquote type=3D"cite">On Sunday, January 3, 2016 at 5:35:33 AM UTC-=
5,
Vicente J. Botet Escriba wrote:
<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex=
;border-left:1px #ccc solid;padding-left:1ex">
<div bgcolor=3D"#FFFFFF" text=3D"#000000">
<div>Le 03/01/2016 04:07, Nicol Bolas a =C3=A9crit=C2=A0:<br>
</div>
<blockquote type=3D"cite">On Wednesday, December 30, 2015 at
8:20:35 AM UTC-5, Vicente J. Botet Escriba wrote:
<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left=
:0.8ex;border-left:1px #ccc solid;padding-left:1ex">
<div bgcolor=3D"#FFFFFF" text=3D"#000000"> Hi,<br>
<br>
n4560 introduce the classes tagged, tagged_pair and
tagged_tuple. Here follows the rationale as described in
n4560:<br>
<br>
<i>[Editor=E2=80=99s note: This type exists so that the
algorithms can return pair- and tuple-like objects
with named accessors, as requested by LEWG. Rather
than create a bunch of one-off class types with no
relation to pair and tuple, I opted instead to create
a general utility. I=E2=80=99ll note that this functional=
ity
can be merged into pair and tuple directly with
minimal breakage, but I opted for now to keep it
separate.]</i><i><br>
</i><br>
<br>
I was wondering if<br>
<br>
=C2=A0=C2=A0=C2=A0 tagged_pair<tag::in(I), tag::fun(Fun)=
><br>
<br>
couldn't be better be represented by the unnamed
aggregate<br>
<br>
=C2=A0=C2=A0=C2=A0 struct {<br>
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 I in;<br>
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 Fun fun;<br>
=C2=A0=C2=A0=C2=A0 }<br>
<br>
which has less noise.<br>
</div>
</blockquote>
<br>
Here's a question.<br>
<br>
From my perspective, the principle reason to use a tuple is
<i>metaprogramming</i>. That is, you're assembling an
aggregation of values from some some user-provided
construct. A tagged tuple has limited metaprogramming value,
but it still has some value in that regard. By tagging types
with names, you can develop interfaces between the sender
and the receiver of a tuple that allow you to more
effectively communicate. Rather than communicating by type
or index, you communicate by a name, thus giving the sending
code the freedom to pick and choose where the element is in
the tuple.<br>
<br>
That's the reason why we need tagged tuples, and the above
case won't even touch that one. Reflection-based aggregate
creation might fix it, but that's for C++20, if even that.<=
br>
<br>
Using a tuple for plain-old multiple-return-values has
always been, to me, of somewhat dubious merit. It's not a
terrible, and it's a solution that'll be far more accep=
table
with structured binding. But using a <i>tagged</i> tuple as
a return value from a concrete function? No; that makes no
sense.<br>
<br>
Clearly you should be returning a struct. But that's where =
I
don't get the point of this proposal. Because, well, why
does it <i>have to be</i> "unnamed"? I mean, are name=
s <i>that
precious</i> that we need to have specialized syntax to do
this? Is this:<br>
<br>
<div 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"><c=
ode>
<div><span style=3D"color:#008">struct</span><span style=3D=
"color:#000"> </span><span style=3D"color:#660">{</span><span style=3D"colo=
r:#008">int</span><span style=3D"color:#000"> x</span><span style=3D"color:=
#660">;</span><span style=3D"color:#000"> </span><span style=3D"color:#008"=
>float</span><span style=3D"color:#000"> y</span><span style=3D"color:#660"=
>}</span><span style=3D"color:#000"> func</span><span style=3D"color:#660">=
()</span><span style=3D"color:#000">
</span><span style=3D"color:#660">{...}</span></div>
</code></div>
<br>
Really that much better than this?<br>
<br>
<div 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"><c=
ode>
<div><span style=3D"color:#008">struct</span><span style=3D=
"color:#000"> </span><span style=3D"color:#606">MeaningfulName</span><span =
style=3D"color:#000"> </span><span style=3D"color:#660">{</span><span style=
=3D"color:#008">int</span><span style=3D"color:#000"> x</span><span style=
=3D"color:#660">;</span><span style=3D"color:#000"> </span><span style=3D"c=
olor:#008">float</span><span style=3D"color:#000"> y</span><span style=3D"c=
olor:#660">};</span><span style=3D"color:#000"><br>
<br>
</span><span style=3D"color:#606">MeaningfulName</span><s=
pan style=3D"color:#000"> func</span><span style=3D"color:#660">()</span><s=
pan style=3D"color:#000">
</span><span style=3D"color:#660">{...}</span></div>
</code></div>
<br>
If the type returned by this function needs to name the
individual multiple values, then that aggregation of values
probably has some meaning. 9 times out of 10, other
functions will want to return that same type. So you're
going to need a named type.<br>
</blockquote>
Here is the problem of naming the result type. When we talk of
returning several values is because we don't have yet one typ=
e
to aggregate them. Most of the time a name is is not
meaningful.<br>
</div>
</blockquote>
<div><br>
See, that right there is what I do not believe. It has not been
my experience that the name of such an aggregation "is not
meaningful".<br>
<br>
Remember, we're not talking about a throwaway MRV case where yo=
u
would use a tuple nowadays. We're talking about an MRV case
where the individual return values <i>need</i> a semantic name,
where the mere type or position of the value does not indicate
its meaning. That's not all or even most MRV cases.<br>
</div>
</blockquote>
No. I'm talking also of those cases, as I don't see a case wher=
e the
position is enough to transport the semantics. DO you have an
example of those cases where pair or tuple would be superior?<br></div>=
</blockquote><div><br>How do you define "superior"?<br><br>I woul=
d say that if the `pair` returned from `map::insert` were `pair<iterator=
, did_insert>` this would be <i>sufficient</i> information for the user =
to figure out what's going on.<br><br>Would a `struct{ iterator insert_=
loc; bool did_insert}` return value be "superior" to that? By som=
e measures, yes. But it would also be <i>longer</i>; it'd require more =
reading. Does that make it inferior to the other? Who decides?<br><br>"=
;Good enough" is good enough to me. `pair<iterator, did_insert>`=
is good enough to be clear to the reader what the return value means. So h=
aving a superior solution is unnecessary, even if we accept that your propo=
sed solution is "superior".<br><br>It stops being a "need&qu=
ot; and becomes a "maybe nice to have." And we shouldn't make=
major language changes for a "maybe nice to have."<br><br></div>=
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bor=
der-left: 1px #ccc solid;padding-left: 1ex;"><div bgcolor=3D"#FFFFFF" text=
=3D"#000000"><br>
<blockquote type=3D"cite">
<div>
So in a better designed system, this would be a struct with two
members. You say that the name of such a struct "is not
meaningful". I contest this. A decent name for such a struct
would be "insertion_state". That's what it is and tha=
t's what it
is used for: telling you the state of the system after
insertion. That name is meaningful.<br>
</div>
</blockquote>
I could buy this one. But I would prefer status_and_value<bool,
Iterator>. We will need to discus it and find a consensus. You
see, naming takes time. I believe this time must be spent when the
type has interest on its own, not just because there is a function
that returns these two values.<br></div></blockquote><div><br>And exact=
ly how would this be changed by `struct{iterator insert_loc; bool did_inser=
t}`? We'd still have to bikeshed about both the name of the individual =
fields and the <i>order</i> of those fields (yours put the "status&quo=
t; first). So what if you add one more thing to the pile of bikeshedding?<b=
r><br>Most importantly of all... who cares? Any (not-deliberately-stupid) n=
ame you pick will be preferable to the impenetrable `pair<iterator, bool=
>`. Stop caring so much about whether a name is <i>perfect</i>. Especial=
ly when you care to the point where you start arguing that we shouldn't=
have names at all just to prevent bikeshedding. <i>Just pick one and move =
on.</i><br><br>Nothing annoys me quite so much as name bikeshedding. Unless=
there's a genuine linguistic/syntactic problem, or the name is <i>prov=
ably</i> ambiguous, or there is an explicit and well-defined naming convent=
ion that would be violated, just take the first one suggested and move on.<=
br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: =
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div bgcolor=3D"#FFFF=
FF" text=3D"#000000">
<blockquote type=3D"cite">
<div>
But then, that comes back to my two points. For this to matter,
you have to have a meaningless aggregation and types which don'=
t
explain what they mean. After all, the only reason you want to
name the return value at all is because the `bool` argument is
unclear as to its meaning. If it were instead:<br>
<br>
<div style=3D"background-color:rgb(250,250,250);border-color:rgb(18=
7,187,187);border-style:solid;border-width:1px;word-wrap:break-word"><code>
<div><span style=3D"color:#008">enum</span><span style=3D"color=
:#000"> </span><span style=3D"color:#008">class</span><span style=3D"color:=
#000">
did_insert </span><span style=3D"color:#660">:</span><span =
style=3D"color:#000"> </span><span style=3D"color:#008">unsigned</span><spa=
n style=3D"color:#000"> </span><span style=3D"color:#008">char</span><span =
style=3D"color:#000"><br>
</span><span style=3D"color:#660">{</span><span style=3D"colo=
r:#000"><br>
=C2=A0 no_insert </span><span style=3D"color:#660">=3D</spa=
n><span style=3D"color:#000"> </span><span style=3D"color:#066">0</span><sp=
an style=3D"color:#660">,</span><span style=3D"color:#000"><br>
=C2=A0 inserted</span><span style=3D"color:#660">,</span><s=
pan style=3D"color:#000"><br>
</span><span style=3D"color:#660">};</span><span style=3D"col=
or:#000"><br>
<br>
pair</span><span style=3D"color:#660"><</span><span styl=
e=3D"color:#000">iterator</span><span style=3D"color:#660">,</span><span st=
yle=3D"color:#000">
did_insert</span><span style=3D"color:#660">></span><spa=
n style=3D"color:#000"> insert</span><span style=3D"color:#660">(...);</spa=
n><span style=3D"color:#000"><br>
</span></div>
</code></div>
<br>
Then the tuple/pair would be perfectly fine. Both values make it
clear what they mean simply from their types. So there is no
need to name them.<br>
</div>
</blockquote>
Ugh, and access with first and second :( Or are you suggesting the
use of get<Iterator>(res) and get<did_insert>(res)?<br></di=
v></blockquote><div><br>I don't care what you use to access the values =
(and I'll care even less with structured binding). What I care about is=
what the reader of the <i>function signature</i> sees. The user sees that =
the function returns an `iterator` value and a `did_insert` value. From tho=
se type names, coupled with the nature of the function, the user can deduce=
what the values mean.<br><br>And therefore, the function has improved clar=
ity over `pair<iterator, bool> insert()`.<br></div><blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;"><div bgcolor=3D"#FFFFFF" text=3D"#000000">
<blockquote type=3D"cite">
<div>
So, here's what I would like to see. Give me a case where the
aggregation is clearly ephemeral, yet the meaning of the
individual values cannot be inferred from the nature of the
function and the typenames of those values. </div>
</blockquote>
A function returning twice the same type ?<br></div></blockquote><div><=
br>OK, <i>why</i> is it "returning twice the same type"? I don=
9;t want some arbitrary "here's a thing that could happen". I=
want a concrete function that performs a useful operation where "retu=
rning twice the same type" is a legitimate operation.<br><br>For insta=
nce, `stoul/stoull`, if we want to replace the optional parameter with a re=
turn value. But I already covered that one with a type alias.<br><br></div>=
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bor=
der-left: 1px #ccc solid;padding-left: 1ex;"><div bgcolor=3D"#FFFFFF" text=
=3D"#000000">
=20
Independently of the language change this could mean. Would you use
unnamedstruct if they were on the language or would you create a
specific named struct?<br></div></blockquote><div><br>If it were magica=
lly available today across all compilers and had been for years (and you re=
asonably resolve all of the various problems with the idea), sure, I'd =
probably use it. <i>Occasionally</i>. I'm not an "always use auto&=
quot; zealot, so I prefer not to do things that require users to use `auto`=
(which is why I typedef my `tuple`s). So I would avoid this construct unle=
ss there was good reason not to.<br><br>But in any case, the question is ir=
relevant. You're not proposing that we go back in time and stick it int=
o C++98. You're proposing it <i>now</i>.<br><br>Well, we don't <i>n=
eed</i> it. With better aliasing support on the sender's side, and stru=
ctured bindings on the receiver's side, the number of cases where posit=
ional return values would be ambiguous would be few if ever.<br><br>So the =
improvements in legibility or program clarity are minimal over the tools we=
're already going to be getting (hopefully).<br></div><blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;"><div bgcolor=3D"#FFFFFF" text=3D"#000000">
<blockquote type=3D"cite">
<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex=
;border-left:1px #ccc solid;padding-left:1ex">
<div bgcolor=3D"#FFFFFF" text=3D"#000000">
<blockquote type=3D"cite"> If so... you need a struct. A <i>named=
</i>
struct. `std::map` proves that, since it has several
interface functions that all return the same
`pair<iterator, bool>`, and all of them have the same
meaning (the bool tells whether insertion happened, the
iterator says where the element is). If two types have the
same functionality and meaning, they are the same type.<br>
</blockquote>
Waiting for your proposal to change this ;-)<br>
</div>
</blockquote>
<div><br>
To change what?<br>
</div>
</blockquote>
A change on the standard library, of course.<br></div></blockquote><div=
><br>This small improvement to clarity is not important enough for a breaki=
ng change. If we get new versions of containers for any "STL2" ty=
pe thing, then obviously this should be resolved. But the committee would r=
ightly reject any breaking proposal just to fix this.<br></div><blockquote =
class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1p=
x #ccc solid;padding-left: 1ex;"><div bgcolor=3D"#FFFFFF" text=3D"#000000">
<blockquote type=3D"cite">
<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex=
;border-left:1px #ccc solid;padding-left:1ex">
<div bgcolor=3D"#FFFFFF" text=3D"#000000">
<blockquote type=3D"cite">How often do you encounter both #1 and
#2? Is this often enough to justify such a language feature?
With structured binding making tuples far more usable for
MRV than they have ever been, I just can't understand why w=
e
need unnamed struct returns like this.<br>
</blockquote>
Take in account that a lot of the current code is written
using references as output parameters. Things are changing
since move semantics, RTO, ...<br>
</div>
</blockquote>
<div><br>
... I don't really know what you're getting at with this
statement.<br>
</div>
</blockquote>
I want to signal that I would expect that there will be more a more
MRV functions in the future, and that it is worth providing a simple
and clear interface for them.<br></div></blockquote><div><br>OK, why do=
you expect that? Equally importantly, why do you think "a lot of the =
current code is written
using references as output parameters"? There really aren=
9;t that many functions out there which <i>try</i> to return multiple value=
s, whether via tuples, reference parameters, or whatever.<br><br>That's=
not to say that it doesn't happen. But we are hardly being overrun by =
functions that have MRVs of some form.<br></div><blockquote class=3D"gmail_=
quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pa=
dding-left: 1ex;"><div bgcolor=3D"#FFFFFF" text=3D"#000000">
<blockquote type=3D"cite">
<div>=C2=A0</div>
<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex=
;border-left:1px #ccc solid;padding-left:1ex">
<div bgcolor=3D"#FFFFFF" text=3D"#000000"> I will replay to you wit=
h
another questions.<br>
<br>
How many times do you find 1) is useful?<br>
=C2=A0=C2=A0=C2=A0 I have not found a single one at the user leve=
l.<br>
<br>
How many times do you have a function that has more than one
output parameters (result)?<br>
=C2=A0=C2=A0=C2=A0 Much more than we used to have.<br>
</div>
</blockquote>
<div><br>
For me? Not very often. Indeed, almost never. Maybe my C++
experience causes me to subconsciously design <i>around</i> the
limitations of single return values, but I have rarely written
functions where I have felt a genuine need to return multiple
things. Perhaps if I had a functional programming background,
I'd use them more frequently. But for me, MRV is not
particularly common.<br>
</div>
</blockquote>
How many time do you then return an aggregate by value? <br></div></blo=
ckquote><div><br>... I don't understand your logic.<br><br>On the one h=
and, you agreed with my notion that named MRVs are about cases where "=
the aggregation <i>itself</i> is
meaningless". And now you seem to be suggesting that <i>any</i=
> aggregate returned by value is meaningless and ought to be an unnamed str=
uct.<br><br>Do you not see how those are different?<br><br>I return lots of=
<i>things</i> by value. Those "things" might be basic types, cla=
sses or simple aggregates. But in all cases, they are <i>a single, conceptu=
al value</i>.<br><br>If I return a 3D vector struct, I am returning <i>a 3D=
vector</i>. It is a <i>single value</i> that happens to have multiple elem=
ents to it. It is not 3 separate return values, even if the type is classif=
ied as a C++ aggregate.<br><br>I return plenty of aggregates by value. And =
in none of those cases would I use an unnamed aggregate, because those aggr=
egations have <i>meaning</i>. In virtually every case, there are functions =
that take them as parameters or types that use them.<br><br>What often happ=
ens to me is that I will start developing with what seems like an MRV. But =
logical use of that API turns it into a meaningful aggregate. For example, =
I have an class that represents a set of images. I need to get the width, h=
eight, possibly depth, etc of the image. At first, I considered just a `Get=
Width`, `GetHeight`, etc. But then I decided to have a `GetDimensions` func=
tion that returns an aggregate of all of them.<br><br>At which point... I s=
tarted using that `Dimensions` type in many places. Instead of having funct=
ions that take a width/height, I just pass `Dimensions`. And internally in =
the ImageSet class, I store a `Dimensions` object; it just makes things sim=
pler.<br><br>I have rarely had the need to return some aggregation that had=
no fundamental meaning beyond that function.<br></div><blockquote class=3D=
"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc s=
olid;padding-left: 1ex;"><div bgcolor=3D"#FFFFFF" text=3D"#000000">
<blockquote type=3D"cite">
<div>
My experience with Lua, which has native (and very cool) support
for multiple return values, bears this out. In that language, I
have used MRVs more frequently than tuple return values in C++.
But at the same time, I have pretty much never wanted to name <i>in=
dividual
return values</i>. In virtually every case, what the multiple
values meant was readily apparent; there was no need to give
each one a semantic name.<br>
<br>
And if there was a need, then I returned a Lua table with named
fields. Now, this is where the analogy breaks down, because Lua
doesn't have static types. But I wouldn't have had any prob=
lem
giving those aggregations of values a name.<br>
<br>
You say that you use MRVs more frequently than you used to. Why?
What is your code doing that needs to throw around multiple
values like this? It is not clear to me what has changed that
causes you to code like this.<br>
</div>
</blockquote>
Move semantic, RVO.<br></div></blockquote><div><br>That's not an an=
swer.<br><br>In order for MRVs to be more frequent now in your code than th=
ey were before, you have to actually be writing functions that return more =
than one conceptual thing to the user. That is, you're not returning a =
value-struct which has some innate meaning; your function is returning two =
or more conceptual values which have little if any coupling (like `map::ins=
ert`).<br><br>What kinds of functions are you writing that <i>require</i> y=
ou to return multiple, uncoupled values?<br></div><blockquote class=3D"gmai=
l_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;=
padding-left: 1ex;"><div bgcolor=3D"#FFFFFF" text=3D"#000000">
<blockquote type=3D"cite">
<div>
</div></blockquote></div></blockquote><blockquote class=3D"gmail_quot=
e" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;paddin=
g-left: 1ex;"><div bgcolor=3D"#FFFFFF" text=3D"#000000"><blockquote type=3D=
"cite">
<div>Indeed, if you call a function that returns named MRVs, you <i>s=
houldn't
use</i> structured bindings on the return value (most of the
time). </div>
</blockquote>
We are on a C++ standard proposals ML. What each one should do or
not do is not important here.<br></div></blockquote><div><br>... what?<=
br><br>How a feature ought to be used by people is very important for discu=
ssion of a proposal. We don't want to add features to the language that=
make it <i>worse</i>.<br><br>Or have we forgotten the `operator&`/`add=
ressof` debacle?<br></div><blockquote class=3D"gmail_quote" style=3D"margin=
: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
</blockquote>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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"https://groups.google.com/a/isocpp.org/group=
/std-proposals/">https://groups.google.com/a/isocpp.org/group/std-proposals=
/</a>.<br />
------=_Part_170_169413274.1451925084408--
------=_Part_169_1785469245.1451925084407--
.
Author: Matthew Woehlke <mwoehlke.floss@gmail.com>
Date: Mon, 04 Jan 2016 12:41:00 -0500
Raw View
On 2016-01-03 12:12, Nicol Bolas wrote:
> It is in this case where `insertion_state` has dubious merit. Because...=
=20
> well, I can't see a real reason why I would write a function that takes i=
t=20
> as a parameter. The two fields basically have nothing to do with one=20
> another. Nor could I see a reason to store one in a larger data structure=
..=20
This, FWIW, is exactly the sort of use case I expect, and indeed is
exactly the sort of use case I've seen in languages that have first
class MRV's (i.e. Python). That is, the values are associated only in
that they are both outputs of a particular function, but don't otherwise
make much sense together.
> enum class did_insert : unsigned char
> {
> no_insert =3D 0,
> inserted,
> };
>=20
> pair<iterator, did_insert> insert(...);
....but this is exactly the same problem; you are creating a type whose
sole purpose is to work around the absence of named MRV's. In fact, I
would argue this is *worse* than named MRV's, because "bool inserted" is
more concise (and easier to work with, as it has the more logical type
'bool' rather than needing to be coerced into a bool). It's also no help
if the type in question is something like 'int'. (At best, you would
need to introduce type aliases...)
Anyway, even if other solutions are possible, they still entail work.
The "work" to lift the restriction against returning anonymous structs
in the standard is... the removal of two words. Nor is it expected that
the work to add this "feature" to compilers will be difficult. Many
already support it to varying degrees, and some may be in the same boat
as the standard, that removing the restriction actually makes them
*less* complicated.
Anyway, as Vicente noted, which is easier to write and understand?:
auto const result =3D map.insert(...);
// Option 1
if (result.second) { ... }
// Option 2
if (get<std::did_insert>(result)) { ... }
// Option 3
if (result.inserted) { ... }
Option 1 required us to look up the return type to know what was
happening (hopefully our IDE helped). Option 2 is verbose and peculiar.
Option 3 is simple and immediately clear.
The argument that your way requires more reading is also dubious.
Compare the code you gave above (six lines!) to:
struct { iterator it; bool inserted; } insert(...);
The anonymous struct is only "longer" if you exclude the cost of the
type aliases / enums / etc. Even then, it's only (notably) longer by the
names of the values, which might have been given *anyway*:
pair<iterator /*inserted_value*/, bool /*was_inserted*/> insert(...);
> On Sunday, January 3, 2016 at 5:35:33 AM UTC-5, Vicente J. Botet Escriba=
=20
> wrote:
>> How many times do you have a function that has more than one output=20
>> parameters (result)?
Any time a non-primitive-type is returned :-).
>> Much more than we used to have.
>=20
> For me? Not very often. Indeed, almost never.
Almost any function with output parameters - and you *know* those exist
- would be better written with MRV's. Things like std::expected=C2=B9 shoul=
d
help, but there are going to continue to be corner cases where no
"canned" complex type is appropriate.
I ended up doing something different (apparently before attempting to
compile the code in question), but I recently was toying with using an
anonymous struct return in another project.
"Almost never" is a slippery argument. There are a lot of corners of the
standard library that I have *literally* never used, especially newer
features, but their inclusion was still felt to be justified.
(=C2=B9 On that note, I literally just a few days ago wrote my own expected
because I really, really needed it for an API I was writing. I
*probably* would not have used anonymous structs, if they'd been available.=
)
> Maybe my C++ experience causes me to subconsciously design *around*
> the limitations of single return values
I would say that's definitely true (based, if nothing else, on an
impression that I do so myself). It would be better to consider their
prevalence in languages such as Python or JS where MRV's (anonymous
objects, in the JS case) are usable without the sorts of jumping through
hoops that current C++ requires to use them.
Related, I would guess there are quite some times that the lack of easy
to use MRV's results in people simply doing without (and producing an
inferior API as a result). This is another key distinction I think needs
to be made... it's not so much that this feature is *required*, as that
it would be *beneficial*. After all, range-based for is not *required*
(we got by many years without it, and in C++11 it can be implemented as
a macro), but it's obviously *beneficial*.
> In virtually every case, what the multiple values meant was readily
> apparent; there was no need to give each one a semantic name.
This is definitely *not* my experience in Python. And, frankly, I'd
probably tend to use anonymous structs for MRV's (if available) over
tuples, just on principle (of them being more self-documenting).
> And if there was a need, then I returned a Lua table with named fields.=
=20
How is that unlike returning an anonymous struct? ;-)
> You say that you use MRVs more frequently than you used to. Why?
....because the pain threshold for doing so is being lowered.
--=20
Matthew
--=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 https://groups.google.com/a/isocpp.org/group/std-propos=
als/.
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 5 Jan 2016 10:12:31 -0800 (PST)
Raw View
------=_Part_197_192111119.1452017551930
Content-Type: multipart/alternative;
boundary="----=_Part_198_1568060656.1452017551931"
------=_Part_198_1568060656.1452017551931
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Monday, January 4, 2016 at 12:41:13 PM UTC-5, Matthew Woehlke wrote:
>
> On 2016-01-03 12:12, Nicol Bolas wrote:=20
> > It is in this case where `insertion_state` has dubious merit. Because..=
..=20
> > well, I can't see a real reason why I would write a function that takes=
=20
> it=20
> > as a parameter. The two fields basically have nothing to do with one=20
> > another. Nor could I see a reason to store one in a larger data=20
> structure.=20
>
> This, FWIW, is exactly the sort of use case I expect, and indeed is=20
> exactly the sort of use case I've seen in languages that have first=20
> class MRV's (i.e. Python). That is, the values are associated only in=20
> that they are both outputs of a particular function, but don't otherwise=
=20
> make much sense together.=20
>
> > enum class did_insert : unsigned char=20
> > {=20
> > no_insert =3D 0,=20
> > inserted,=20
> > };=20
> >=20
> > pair<iterator, did_insert> insert(...);=20
>
> ...but this is exactly the same problem; you are creating a type whose=20
> sole purpose is to work around the absence of named MRV's. In fact, I=20
> would argue this is *worse* than named MRV's, because "bool inserted" is=
=20
> more concise (and easier to work with, as it has the more logical type=20
> 'bool' rather than needing to be coerced into a bool). It's also no help=
=20
> if the type in question is something like 'int'. (At best, you would=20
> need to introduce type aliases...)=20
>
> Anyway, even if other solutions are possible, they still entail work.=20
> The "work" to lift the restriction against returning anonymous structs=20
> in the standard is... the removal of two words.
No, it isn't.
As previously discussed, each function that returns an unnamed struct will=
=20
be returning a *different type*, even if they look the same. Even declaring=
=20
and defining such functions in different places has to use reworked=20
language, because technically speaking, the declaration and definition are=
=20
returning *different types*. Which isn't allowed in C++.
So the only way to make this a "two word" change is to restrict its use to=
=20
only being for inlined functions. If you want to be able to declare and=20
define them in different places, then you must either add your `auto`=20
feature or you have to make unnamed types the same for the same function=20
overload. Either way adds wording, and therefore it's not a "two word"=20
change.
Given that:
Nor is it expected that=20
> the work to add this "feature" to compilers will be difficult.
I'd say it's rather premature to declare how difficult it would be to add=
=20
this feature. Especially since your `auto` feature has some technical=20
issues left to work out (as I understand it).
Many=20
> already support it to varying degrees, and some may be in the same boat=
=20
> as the standard, that removing the restriction actually makes them=20
> *less* complicated.=20
>
> Anyway, as Vicente noted, which is easier to write and understand?:=20
>
> auto const result =3D map.insert(...);=20
>
> // Option 1=20
> if (result.second) { ... }=20
>
> // Option 2=20
> if (get<std::did_insert>(result)) { ... }=20
>
> // Option 3=20
> if (result.inserted) { ... }=20
>
> Option 1 required us to look up the return type to know what was=20
> happening (hopefully our IDE helped). Option 2 is verbose and peculiar.=
=20
> Option 3 is simple and immediately clear.
>
You don't want to use an alias or an enum with `pair`? You think it won't=
=20
be as clear to the reader at the destination site? Fine. But why does the=
=20
return struct *have to be* unnamed?
Also, let's not forget Option 4:
auto {it, inserted} =3D map.insert();
if(inserted) {...}
I like that better than any of them. It lets the person writing the code=20
decide what the names mean. And this option is likely coming to C++, one=20
way or another.
So C++ has Option 3 via a named type. C++ will have Option 4 via structured=
=20
binding. So where is the space for your unnamed type?
The argument that your way requires more reading is also dubious.=20
> Compare the code you gave above (six lines!) to:=20
>
> struct { iterator it; bool inserted; } insert(...);=20
>
You forget: there are *dozens* of functions that would use this. There are=
=20
two overloads of `insert`=20
<http://en.cppreference.com/w/cpp/container/unordered_map/insert>, two=20
overloads of `insert_or_assign`=20
<http://en.cppreference.com/w/cpp/container/unordered_map/insert_or_assign>=
,=20
`emplace` <http://en.cppreference.com/w/cpp/container/map/emplace>, and two=
=20
overloads of `try_emplace`=20
<http://en.cppreference.com/w/cpp/container/map/try_emplace>. That's 7=20
functions on std::map alone. std::set, std::unordered_map, and=20
std::unordered_set all have similar functions that use this type.
Those "six lines"? They only have to be typed *once*.
Ultimately, this *should have been* a named type all along. Having to type=
=20
`struct{iterator it, bool inserted}` dozens of times makes it exceedingly=
=20
easy to make a typo.
> On Sunday, January 3, 2016 at 5:35:33 AM UTC-5, Vicente J. Botet Escriba=
=20
> > wrote:=20
> >> How many times do you have a function that has more than one output=20
> >> parameters (result)?=20
>
> Any time a non-primitive-type is returned :-).=20
>
> >> Much more than we used to have.=20
> >=20
> > For me? Not very often. Indeed, almost never.=20
>
> Almost any function with output parameters - and you *know* those exist=
=20
> - would be better written with MRV's. Things like std::expected=C2=B9 sho=
uld=20
> help, but there are going to continue to be corner cases where no=20
> "canned" complex type is appropriate.
>
First, I disagree that "almost any function with output parameters" ought=
=20
to use MRVs. `optional` and `expected` cover a good number of those cases.=
=20
Most of the rest are either things like `stoi` where it's returning extra=
=20
information, or places where you really need an output *parameter*. You're=
=20
filling in memory that someone else allocated. Nowadays, we might use a=20
`span<unsigned char>` or whatever, but it's still ultimately an output=20
parameter no matter how you specify it.
Second, do we want language features like this for "corner cases?" How many=
=20
such corner cases do you encounter?
And do we need such corner case features when we have people practically=20
frothing at the mouth to *abuse* it?
> Maybe my C++ experience causes me to subconsciously design *around*=20
> > the limitations of single return values=20
>
> I would say that's definitely true (based, if nothing else, on an=20
> impression that I do so myself). It would be better to consider their=20
> prevalence in languages such as Python or JS where MRV's (anonymous=20
> objects, in the JS case) are usable without the sorts of jumping through=
=20
> hoops that current C++ requires to use them.=20
>
> Related, I would guess there are quite some times that the lack of easy=
=20
> to use MRV's results in people simply doing without (and producing an=20
> inferior API as a result). This is another key distinction I think needs=
=20
> to be made... it's not so much that this feature is *required*, as that=
=20
> it would be *beneficial*. After all, range-based for is not *required*=20
> (we got by many years without it, and in C++11 it can be implemented as=
=20
> a macro), but it's obviously *beneficial*.
>
Agreed but... that doesn't explain why we specifically need *unnamed*=20
structs to fill that gap.
There are two major problems with using `tuple` to fill that gap.
1) It is *exceedingly* painful for the receiving code to use.
2) It provides no useful semantic information beyond the typenames.
Structured binding solves problem #1. But it also solves most of problem=20
#2, at least from the perspective of someone reading the receiving code.
So the space for unnamed structs would seem to be for reading the function=
=20
declaration. Except... it could just be a named struct. And as you agreed=
=20
to in your next post, it ought to be a named struct if the aggregation is=
=20
used in multiple places.
So the space for this feature seems decidedly small. It must be a one-off=
=20
usage where typenames aren't enough to deduce the meaning.
> In virtually every case, what the multiple values meant was readily=20
> > apparent; there was no need to give each one a semantic name.=20
>
> This is definitely *not* my experience in Python. And, frankly, I'd=20
> probably tend to use anonymous structs for MRV's (if available) over=20
> tuples, just on principle (of them being more self-documenting).
>
.... How is it more self-documenting?
auto x =3D foo();
What is `x`? Is it one value? Twenty? I don't know; I have to go look it up=
..
tuple<int, float, std::string> x =3D foo();
I wouldn't go so far as to call that "self-documenting" but at least it has=
=20
*substance*. It gives me the chance to at least *guess* at what the=20
interface might mean, given the name of the function called and the return=
=20
types.
pair<iterator, did_insert> x =3D mapy.insert(...);
Looking at that, I can make educated guesses about what those fields are.=
=20
Odds are good that those guesses will be correct. That's far more=20
"self-documenting" to me than `auto x =3D foo();`. So is:
auto {it, did_insert} =3D mapy.insert(...);
But at the very least, there could be this:
Typename x =3D foo();
This has less substance, but I at least have two pieces of information I=20
can use to figure out what this means. I have the function name and a type=
=20
name.
> And if there was a need, then I returned a Lua table with named fields.=
=20
>
> How is that unlike returning an anonymous struct? ;-)
>
Because Lua's not a static language. In Lua, I can do this: `foo(bar())`.=
=20
If `bar` returned 5 values via positional MRV, `foo` would take those 5=20
values. If `bar` returned a table with named fields, that's what `foo`=20
would get. So regardless of how I return those MRVs, I have lost none of=20
the expressive power of the language.
If I return an unnamed struct, I cannot chain calls with it. I must use a=
=20
named type in that circumstance. So unnamed structs have a restriction to=
=20
my expressive power which named structs and `tuple`s do not have.
---------
In reply to your next message:
--------
On Monday, January 4, 2016 at 12:08:56 PM UTC-5, Matthew Woehlke wrote:
>
> On 2016-01-02 22:07, Nicol Bolas wrote:=20
> > [...]=20
> > Clearly you should be returning a struct. But that's where I don't get=
=20
> the=20
> > point of this proposal. Because, well, why does it *have to be*=20
> "unnamed"?=20
> > I mean, are names *that precious*=20
>
> Yes. Imagine you have five methods in a class that have MRV's. What do=20
> you name them?
>
I can "imagine" a lot. That doesn't mean it's worth adding a feature to the=
=20
language for.
Show me 5 actual methods in the same class which return MRVs that follow=20
the 2 principles that I outlined and you agreed with. That is, tuples would=
=20
be inappropriate because the typenames are non-indicative of the meaning.=
=20
And no other code uses that same aggregation of values with that meaning.
`map::insert` and its ilk don't follow principle 2, because multiple=20
overloads and different functions return the same aggregation which has the=
=20
same meaning. So they're not examples.
Naming things is *hard*. Naming multiple return values=C2=B9 is *especially=
*=20
> hard, and bloats the API unnecessarily.
I'm sorry, but I have a problem considering inserting a typename to=20
constitute "bloat".
The more often MRV's are used, the worse the problem becomes.=20
>
> See also Vicente's response to this point. Remember, we're talking about=
=20
> the cost of naming *one-off* structures.
>
No, we're talking about the cost of naming one-off structures who's=20
typenames don't provide sufficient semantic information to know what they=
=20
mean. That's what you agreed to when you agreed with principle #1.
The only example I've run into (in the standard library, at least) is=20
`stoi` and its ilk. What other real code examples can you give?
On the flip side, I will continue to maintain that the prohibition is=20
> unnecessary in the first place. If we were adding complexity to the=20
> language, I would be inclined to give greater weight to your arguments.=
=20
> But we're not. We're *removing* a restriction that no longer makes=20
> sense. The net change to the standard is a *removal*... of a whole two=20
> words, at that. Moreover, that restriction is not even uniformly=20
> implemented in current compilers.=20
>
> Note also that *allowing* anonymous struct returns is different from=20
> *requiring* them; folks that think they should be named will still be=20
> able to name them :-).
>
Except that we'll also have to deal with people who won't name types that=
=20
ought to have names. Just as we have to deal with tuple-happy people.
Giving people carte blanche to force me to type `auto` more is not=20
something I look forward to.
> So it seems to me that unnamed struct return values would only be useful=
=20
> in=20
> > cases where:=20
> >=20
> > 1) `tuple` is inappropriate. This would suggest that the semantic=20
> meaning=20
> > of each independent return value is both significant and not obvious=20
> from=20
> > just the type and function name (`pair` returned from `map::insert` is =
a=20
> > good example). And `tagged_tuple`, well, sucks at this for obvious=20
> reasons.=20
>
> Sure.=20
>
> > 2) That function is the *only function* that returns this type or does=
=20
> > anything with it in any way. If the function has even one other=20
> overload,=20
> > then you ought to use a named type.=20
>
> Fair enough.=20
>
> > How often do you encounter both #1 and #2? Is this often enough to=20
> justify=20
> > such a language feature?=20
>
> Maybe not on its own. However, these are also not the only reasons. Some=
=20
> have even suggested that IRTVPDUA especially has its major justification=
=20
> *apart from* being able to return anonymous structs. Personally, I am=20
> somewhat indifferent on that point; I consider that IRTVPDUA is just a=20
> useful and obvious feature, without being strongly opinionated on=20
> whether anonymous structs or other things are the most important use case=
..
>
Maybe you've mixed up the threads, but we're talking about returning=20
unnamed structs. Your `auto` feature is important to that discussion only=
=20
in that it provides a way to declare and define such functions. But your=20
`auto` feature is not strictly *necessary* to it, nor (as you point out) is=
=20
the justification for your `auto` feature solely to support unnamed structs=
..
So that's a tangential argument.
=20
> > With structured binding making tuples far more usable for MRV than=20
> > they have ever been, I just can't understand why we need unnamed=20
> > struct returns like this.
>
> Structured binding, if anything, makes this feature (returning anonymous=
=20
> structs) *more* useful. You already gave the main reason, in your (1)=20
> above.
>
How? It makes returning `tuple`s more digestible because the writer of the=
=20
receiving code can give the unnamed fields a semantic name (and not have to=
=20
type a bunch of pointless `get<>` calls or use `std::tie`). It makes=20
returning unnamed structs less useful because `tuple` becomes a legitimate=
=20
MRV solution, rather than a massive eyesore. Readers of the code have a=20
semantic name they can see (even if it's not the one the writer of the=20
function might have picked).
--=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 https://groups.google.com/a/isocpp.org/group/std-propos=
als/.
------=_Part_198_1568060656.1452017551931
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Monday, January 4, 2016 at 12:41:13 PM UTC-5, Matthew Woehlke wrote:<blo=
ckquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-=
left: 1px #ccc solid;padding-left: 1ex;">On 2016-01-03 12:12, Nicol Bolas w=
rote:
<br>> It is in this case where `insertion_state` has dubious merit. Beca=
use...=20
<br>> well, I can't see a real reason why I would write a function t=
hat takes it=20
<br>> as a parameter. The two fields basically have nothing to do with o=
ne=20
<br>> another. Nor could I see a reason to store one in a larger data st=
ructure.=20
<br>
<br>This, FWIW, is exactly the sort of use case I expect, and indeed is
<br>exactly the sort of use case I've seen in languages that have first
<br>class MRV's (i.e. Python). That is, the values are associated only =
in
<br>that they are both outputs of a particular function, but don't othe=
rwise
<br>make much sense together.
<br>
<br>> enum class did_insert : unsigned char
<br>> {
<br>> =C2=A0 no_insert =3D 0,
<br>> =C2=A0 inserted,
<br>> };
<br>>=20
<br>> pair<iterator, did_insert> insert(...);
<br>
<br>...but this is exactly the same problem; you are creating a type whose
<br>sole purpose is to work around the absence of named MRV's. In fact,=
I
<br>would argue this is *worse* than named MRV's, because "bool in=
serted" is
<br>more concise (and easier to work with, as it has the more logical type
<br>'bool' rather than needing to be coerced into a bool). It's=
also no help
<br>if the type in question is something like 'int'. (At best, you =
would
<br>need to introduce type aliases...)
<br>
<br>Anyway, even if other solutions are possible, they still entail work.
<br>The "work" to lift the restriction against returning anonymou=
s structs
<br>in the standard is... the removal of two words.</blockquote><div><br>No=
, it isn't.<br><br>As previously discussed, each function that returns =
an unnamed struct will be returning a <i>different type</i>, even if they l=
ook the same. Even declaring and defining such functions in different place=
s has to use reworked language, because technically speaking, the declarati=
on and definition are returning <i>different types</i>. Which isn't all=
owed in C++.<br><br>So the only way to make this a "two word" cha=
nge is to restrict its use to only being for inlined functions. If you want=
to be able to declare and define them in different places, then you must e=
ither add your `auto` feature or you have to make unnamed types the same fo=
r the same function overload. Either way adds wording, and therefore it'=
;s not a "two word" change.<br><br>Given that:<br><br></div><bloc=
kquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-l=
eft: 1px #ccc solid;padding-left: 1ex;">Nor is it expected that
<br>the work to add this "feature" to compilers will be difficult=
..</blockquote><div><br>I'd say it's rather premature to declare how=
difficult it would be to add this feature. Especially since your `auto` fe=
ature has some technical issues left to work out (as I understand it).<br><=
br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: =
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">Many
<br>already support it to varying degrees, and some may be in the same boat
<br>as the standard, that removing the restriction actually makes them
<br>*less* complicated.
<br>
<br>Anyway, as Vicente noted, which is easier to write and understand?:
<br>
<br>=C2=A0 auto const result =3D map.insert(...);
<br>
<br>=C2=A0 // Option 1
<br>=C2=A0 if (result.second) { ... }
<br>
<br>=C2=A0 // Option 2
<br>=C2=A0 if (get<std::did_insert>(result)) { ... }
<br>
<br>=C2=A0 // Option 3
<br>=C2=A0 if (result.inserted) { ... }
<br>
<br>Option 1 required us to look up the return type to know what was
<br>happening (hopefully our IDE helped). Option 2 is verbose and peculiar.
<br>Option 3 is simple and immediately clear.<br></blockquote><div><br>You =
don't want to use an alias or an enum with `pair`? You think it won'=
;t be as clear to the reader at the destination site? Fine. But why does th=
e return struct <i>have to be</i> unnamed?<br><br>Also, let's not forge=
t Option 4:<br><br><div class=3D"prettyprint" style=3D"background-color: rg=
b(250, 250, 250); border-color: rgb(187, 187, 187); border-style: solid; bo=
rder-width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div c=
lass=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-pre=
ttify">auto</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">it</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> inserted</span><span style=3D"col=
or: #660;" 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">=3D</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> map</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">.</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
">insert</span><span style=3D"color: #660;" class=3D"styled-by-prettify">()=
;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br><=
/span><span style=3D"color: #008;" class=3D"styled-by-prettify">if</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">inserted</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: #660;" =
class=3D"styled-by-prettify">{...}</span></div></code></div><br>I like that=
better than any of them. It lets the person writing the code decide what t=
he names mean. And this option is likely coming to C++, one way or another.=
<br><br>So C++ has Option 3 via a named type. C++ will have Option 4 via st=
ructured binding. So where is the space for your unnamed type?<br><br></div=
><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bo=
rder-left: 1px #ccc solid;padding-left: 1ex;">
The argument that your way requires more reading is also dubious.
<br>Compare the code you gave above (six lines!) to:
<br>
<br>=C2=A0 struct { iterator it; bool inserted; } insert(...);
<br></blockquote><div><br>You forget: there are <i>dozens</i> of functions =
that would use this. There are two overloads of <a href=3D"http://en.cppref=
erence.com/w/cpp/container/unordered_map/insert">`insert`</a>, two overload=
s of <a href=3D"http://en.cppreference.com/w/cpp/container/unordered_map/in=
sert_or_assign">`insert_or_assign`</a>, <a href=3D"http://en.cppreference.c=
om/w/cpp/container/map/emplace">`emplace`</a>, and two overloads of <a href=
=3D"http://en.cppreference.com/w/cpp/container/map/try_emplace">`try_emplac=
e`</a>. That's 7 functions on std::map alone. std::set, std::unordered_=
map, and std::unordered_set all have similar functions that use this type.<=
br><br>Those "six lines"? They only have to be typed <i>once</i>.=
<br><br>Ultimately, this <i>should have been</i> a named type all along. Ha=
ving to type `struct{iterator it, bool inserted}` dozens of times makes it =
exceedingly easy to make a typo.<br><br></div><blockquote class=3D"gmail_qu=
ote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padd=
ing-left: 1ex;">
> On Sunday, January 3, 2016 at 5:35:33 AM UTC-5, Vicente J. Botet Escri=
ba=20
<br>> wrote:
<br>>> How many times do you have a function that has more than one o=
utput=20
<br>>> parameters (result)?
<br>
<br>Any time a non-primitive-type is returned :-).
<br>
<br>>> =C2=A0 =C2=A0 Much more than we used to have.
<br>>=20
<br>> For me? Not very often. Indeed, almost never.
<br>
<br>Almost any function with output parameters - and you *know* those exist
<br>- would be better written with MRV's. Things like std::expected=C2=
=B9 should
<br>help, but there are going to continue to be corner cases where no
<br>"canned" complex type is appropriate.<br></blockquote><div><b=
r>First, I disagree that "almost any function with output parameters&q=
uot; ought to use MRVs. `optional` and `expected` cover a good number of th=
ose cases. Most of the rest are either things like `stoi` where it's re=
turning extra information, or places where you really need an output <i>par=
ameter</i>. You're filling in memory that someone else allocated. Nowad=
ays, we might use a `span<unsigned char>` or whatever, but it's s=
till ultimately an output parameter no matter how you specify it.<br></div>=
<div><br>Second, do we want language features like this for "corner ca=
ses?" How many such corner cases do you encounter?<br><br>And do we ne=
ed such corner case features when we have people practically frothing at th=
e mouth to <i>abuse</i> it?<br><br></div><blockquote class=3D"gmail_quote" =
style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-l=
eft: 1ex;">
> Maybe my C++ experience causes me to subconsciously design *around*
<br>> the limitations of single return values
<br>
<br>I would say that's definitely true (based, if nothing else, on an
<br>impression that I do so myself). It would be better to consider their
<br>prevalence in languages such as Python or JS where MRV's (anonymous
<br>objects, in the JS case) are usable without the sorts of jumping throug=
h
<br>hoops that current C++ requires to use them.
<br>
<br>Related, I would guess there are quite some times that the lack of easy
<br>to use MRV's results in people simply doing without (and producing =
an
<br>inferior API as a result). This is another key distinction I think need=
s
<br>to be made... it's not so much that this feature is *required*, as =
that
<br>it would be *beneficial*. After all, range-based for is not *required*
<br>(we got by many years without it, and in C++11 it can be implemented as
<br>a macro), but it's obviously *beneficial*.<br></blockquote><div><br=
>Agreed but... that doesn't explain why we specifically need <i>unnamed=
</i> structs to fill that gap.<br><br>There are two major problems with usi=
ng `tuple` to fill that gap.<br><br>1) It is <i>exceedingly</i> painful for=
the receiving code to use.<br><br>2) It provides no useful semantic inform=
ation beyond the typenames.<br><br>Structured binding solves problem #1. Bu=
t it also solves most of problem #2, at least from the perspective of someo=
ne reading the receiving code.<br><br>So the space for unnamed structs woul=
d seem to be for reading the function declaration. Except... it could just =
be a named struct. And as you agreed to in your next post, it ought to be a=
named struct if the aggregation is used in multiple places.<br><br>So the =
space for this feature seems decidedly small. It must be a one-off usage wh=
ere typenames aren't enough to deduce the meaning.<br><br></div><blockq=
uote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-lef=
t: 1px #ccc solid;padding-left: 1ex;">
> In virtually every case, what the multiple values meant was readily
<br>> apparent; there was no need to give each one a semantic name.
<br>
<br>This is definitely *not* my experience in Python. And, frankly, I'd
<br>probably tend to use anonymous structs for MRV's (if available) ove=
r
<br>tuples, just on principle (of them being more self-documenting).<br></b=
lockquote><div><br>... How is it more self-documenting?<br><br><div class=
=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); border-colo=
r: rgb(187, 187, 187); border-style: solid; border-width: 1px; word-wrap: b=
reak-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span=
style=3D"color: #008;" class=3D"styled-by-prettify">auto</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> x </span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> foo</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">();</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"><br></span></div></code></div><br>What is `x`? Is it on=
e value? Twenty? I don't know; I have to go look it up.<br><br><div cla=
ss=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); border-co=
lor: rgb(187, 187, 187); border-style: solid; border-width: 1px; word-wrap:=
break-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify">tuple</span><span st=
yle=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: #000;" c=
lass=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"s=
tyled-by-prettify">float</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> std</span><span style=3D"color: #660;" class=3D"styled-by-prettify">:=
:</span><span style=3D"color: #008;" class=3D"styled-by-prettify">string</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">></span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> x </span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> foo</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">();</span></div></code></div><br>I woul=
dn't go so far as to call that "self-documenting" but at leas=
t it has <i>substance</i>. It gives me the chance to at least <i>guess</i> =
at what the interface might mean, given the name of the function called and=
the return types.<br><br><div class=3D"prettyprint" style=3D"background-co=
lor: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-style: so=
lid; border-width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"=
><div class=3D"subprettyprint"><span style=3D"color: #000;" class=3D"styled=
-by-prettify">pair</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify"><</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"> did_inse=
rt</span><span style=3D"color: #660;" class=3D"styled-by-prettify">></sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"> x </span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> mapy</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">.</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify">insert</span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">(...);</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br></span></div></code></div><br>Looking at that,=
I can make educated guesses about what those fields are. Odds are good tha=
t those guesses will be correct. That's far more "self-documenting=
" to me than `auto x =3D foo();`. So is:<br><br><div class=3D"prettypr=
int" 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"co=
lor: #008;" class=3D"styled-by-prettify">auto</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify">it</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
did_insert</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: #660;" class=3D"styled-by-prettify">=3D</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> mapy</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">.</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify">insert</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">(...);</span></div></code></div><br>But a=
t the very least, there could be this:<br><br><div class=3D"prettyprint" st=
yle=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 18=
7); border-style: solid; border-width: 1px; word-wrap: break-word;"><code c=
lass=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #6=
06;" class=3D"styled-by-prettify">Typename</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> x </span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> foo</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">();</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"><br></span></div></code></div><br>This has less substance, but I at le=
ast have two pieces of information I can use to figure out what this means.=
I have the function name and a type name.<br><br></div><blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;">
> And if there was a need, then I returned a Lua table with named fields=
..=20
<br>
<br>How is that unlike returning an anonymous struct? ;-)<br></blockquote><=
div><br>Because Lua's not a static language. In Lua, I can do this: `fo=
o(bar())`. If `bar` returned 5 values via positional MRV, `foo` would take =
those 5 values. If `bar` returned a table with named fields, that's wha=
t `foo` would get. So regardless of how I return those MRVs, I have lost no=
ne of the expressive power of the language.<br><br>If I return an unnamed s=
truct, I cannot chain calls with it. I must use a named type in that circum=
stance. So unnamed structs have a restriction to my expressive power which =
named structs and `tuple`s do not have.<br><br>---------<br>In reply to you=
r next message:<br>--------<br><br>On Monday, January 4, 2016 at 12:08:56 P=
M UTC-5, Matthew Woehlke wrote:<blockquote class=3D"gmail_quote" style=3D"m=
argin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"=
>On 2016-01-02 22:07, Nicol Bolas wrote:
<br>> [...]
<br>> Clearly you should be returning a struct. But that's where I d=
on't get the=20
<br>> point of this proposal. Because, well, why does it *have to be* &q=
uot;unnamed"?=20
<br>> I mean, are names *that precious*=20
<br>
<br>Yes. Imagine you have five methods in a class that have MRV's. What=
do
<br>you name them?<br></blockquote><div><br>I can "imagine" a lot=
.. That doesn't mean it's worth adding a feature to the language for=
..<br><br>Show
me 5 actual methods in the same class which return MRVs that follow the 2
principles that I outlined and you agreed with. That is, tuples would=20
be inappropriate because the typenames are non-indicative of the=20
meaning. And no other code uses that same aggregation of values with=20
that meaning.<br><br>`map::insert` and its ilk don't follow principle 2=
, because=20
multiple overloads and different functions return the same aggregation=20
which has the same meaning. So they're not examples.<br><br></div><bloc=
kquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-l=
eft: 1px #ccc solid;padding-left: 1ex;">
Naming things is *hard*. Naming multiple return values=C2=B9 is *especially=
*
<br>hard, and bloats the API unnecessarily.</blockquote><div><br>I'm so=
rry, but I have a problem considering inserting a typename to constitute &q=
uot;bloat".<br><br></div><blockquote class=3D"gmail_quote" style=3D"ma=
rgin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">=
The more often MRV's are used,
the worse the problem becomes.
<br></blockquote><blockquote style=3D"margin: 0px 0px 0px 0.8ex; border-lef=
t: 1px solid rgb(204, 204, 204); padding-left: 1ex;" class=3D"gmail_quote">=
<div><br></div></blockquote><blockquote class=3D"gmail_quote" style=3D"marg=
in: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
See also Vicente's response to this point. Remember, we're talking =
about
<br>the cost of naming *one-off* structures.<br></blockquote><div><br>No, w=
e're talking about the cost of naming one-off structures who's type=
names don't provide sufficient semantic information to know what they m=
ean. That's what you agreed to when you agreed with principle #1.<br><b=
r>The only example I've run into (in the standard library, at
least) is `stoi` and its ilk. What other real code examples can you=20
give?<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;mar=
gin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
On the flip side, I will continue to maintain that the prohibition is
<br>unnecessary in the first place. If we were adding complexity to the
<br>language, I would be inclined to give greater weight to your arguments.
<br>But we're not. We're *removing* a restriction that no longer ma=
kes
<br>sense. The net change to the standard is a *removal*... of a whole two
<br>words, at that. Moreover, that restriction is not even uniformly
<br>implemented in current compilers.
<br>
<br>Note also that *allowing* anonymous struct returns is different from
<br>*requiring* them; folks that think they should be named will still be
<br>able to name them :-).<br></blockquote><div><br>Except that we'll=
=20
also have to deal with people who won't name types that ought to have=
=20
names. Just as we have to deal with tuple-happy people.<br><br>Giving peopl=
e carte blanche to force me to type `auto` more is not something I look for=
ward to.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;=
margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
> So it seems to me that unnamed struct return values would only be usef=
ul in=20
<br>> cases where:
<br>>=20
<br>> 1) `tuple` is inappropriate. This would suggest that the semantic =
meaning=20
<br>> of each independent return value is both significant and not obvio=
us from=20
<br>> just the type and function name (`pair` returned from `map::insert=
` is a=20
<br>> good example). And `tagged_tuple`, well, sucks at this for obvious=
reasons.
<br>
<br>Sure.
<br>
<br>> 2) That function is the *only function* that returns this type or =
does=20
<br>> anything with it in any way. If the function has even one other ov=
erload,=20
<br>> then you ought to use a named type.
<br>
<br>Fair enough.
<br>
<br>> How often do you encounter both #1 and #2? Is this often enough to=
justify=20
<br>> such a language feature?
<br>
<br>Maybe not on its own. However, these are also not the only reasons. Som=
e
<br>have even suggested that IRTVPDUA especially has its major justificatio=
n
<br>*apart from* being able to return anonymous structs. Personally, I am
<br>somewhat indifferent on that point; I consider that IRTVPDUA is just a
<br>useful and obvious feature, without being strongly opinionated on
<br>whether anonymous structs or other things are the most important use ca=
se.<br></blockquote><div><br>Maybe
you've mixed up the threads, but we're talking about returning unn=
amed=20
structs. Your `auto` feature is important to that discussion only in=20
that it provides a way to declare and define such functions. But your=20
`auto` feature is not strictly <i>necessary</i> to it, nor (as you point ou=
t) is the justification for your `auto` feature solely to support unnamed s=
tructs.<br><br>So that's a tangential argument.<br>=C2=A0</div><blockqu=
ote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left=
: 1px #ccc solid;padding-left: 1ex;">
> With structured binding making tuples far more usable for MRV than
<br>> they have ever been, I just can't understand why we need unnam=
ed
<br>> struct returns like this.<br>
<br>Structured binding, if anything, makes this feature (returning anonymou=
s
<br>structs) *more* useful. You already gave the main reason, in your (1) a=
bove.<br></blockquote><div><br>How?
It makes returning `tuple`s more digestible because the writer of the=20
receiving code can give the unnamed fields a semantic name (and not have
to type a bunch of pointless `get<>` calls or use `std::tie`). It
makes returning unnamed structs less useful because `tuple` becomes a=20
legitimate MRV solution, rather than a massive eyesore. Readers of the=20
code have a semantic name they can see (even if it's not the one the=20
writer of the function might have picked).<br></div><br></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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"https://groups.google.com/a/isocpp.org/group=
/std-proposals/">https://groups.google.com/a/isocpp.org/group/std-proposals=
/</a>.<br />
------=_Part_198_1568060656.1452017551931--
------=_Part_197_192111119.1452017551930--
.
Author: Matthew Woehlke <mwoehlke.floss@gmail.com>
Date: Tue, 05 Jan 2016 14:30:29 -0500
Raw View
On 2016-01-05 13:12, Nicol Bolas wrote:
> On Monday, January 4, 2016 at 12:41:13 PM UTC-5, Matthew Woehlke wrote:
>> Anyway, even if other solutions are possible, they still entail work.=20
>> The "work" to lift the restriction against returning anonymous structs=
=20
>> in the standard is... the removal of two words.
>=20
> No, it isn't.
If that's true, I would sincerely appreciate *constructive* feedback as
to what other changes need to be made.
However...
> As previously discussed, each function that returns an unnamed struct wil=
l=20
> be returning a *different type*, even if they look the same.
I've repeatedly stated that I don't consider this a problem; that, in
fact, I consider it *a good thing*.
> Even declaring and defining such functions in different places has to
> use reworked language, because technically speaking, the declaration
> and definition are returning *different types*. Which isn't allowed in C+=
+.
I certainly concede that loosening [dcl.fct]/11 runs into this problem.
*IF* we do not also have IRTVPDUA. This is why the latter is (currently)
part of the proposal for the former. It indeed does not make sense to
have the latter without the former.
> So the only way to make this a "two word" change is to restrict its use t=
o=20
> only being for inlined functions.
Okay, then to be fair, I will clarify that when I make that statement, I
am considering the change that is needed *in addition* to the IRTVPDUA
changes (which have their own additional justification besides loosening
[dcl.fct]/11).
> Given that:
>=20
>> Nor is it expected that the work to add this "feature" to
>> compilers will be difficult.
>=20
> I'd say it's rather premature to declare how difficult it would be to add=
=20
> this feature. Especially since your `auto` feature has some technical=20
> issues left to work out (as I understand it).
There is a non-trivial issue (related to templates) that does still need
to be specified. I would however consider it "worked out".
I would also encourage you to check the current version of the proposal
for an example of how both GCC and ICC *already do support* returning
anonymous structs from functions. (They do. Really. It's necessary to
employ a rather circuitous technique to "name" - via template type
deduction - the return type, but there appears to be no fundamental
problem returning a struct that was defined as anonymous. This suggests
that the overhead of loosening [dcl.fct]/11 either for inline
definitions or given IRTVPDUA also, may be minimal or even trivial. Then
there is MSVC, which just supports this already, although some
modification may be required to align that support with how it would be
specified in the standard.)
> You don't want to use an alias or an enum with `pair`? You think it won't=
=20
> be as clear to the reader at the destination site? Fine. But why does the=
=20
> return struct *have to be* unnamed?
Why does it *have to be named*? Naming things has a cost, too.
> You forget: there are *dozens* of functions that would use this.=20
> There are [list of 7 examples]. std::set, std::unordered_map, and
> std::unordered_set all have similar functions that use this type.
>=20
> Those "six lines"? They only have to be typed *once*.
Really? std::[unordered_]{map,set} will all use the same struct defined
in namespace std? (As a template struct, I guess?) Otherwise, your
example is just about break-even.
Granted, perhaps this *particular example* should use a named struct.
What about places that *don't* have many functions returning the same
value set?
>>> On Sunday, January 3, 2016 at 5:35:33 AM UTC-5, Vicente J. Botet Escrib=
a=20
>>> wrote:=20
>>>> How many times do you have a function that has more than one output=20
>>>> parameters (result)?=20
>>>
>>> For me? Not very often. Indeed, almost never.=20
>>
>> Almost any function with output parameters - and you *know* those exist=
=20
>> - would be better written with MRV's. Things like std::expected=C2=B9 sh=
ould=20
>> help, but there are going to continue to be corner cases where no=20
>> "canned" complex type is appropriate.
>=20
> First, I disagree that "almost any function with output parameters"
> ought to use MRVs. `optional` and `expected` cover a good number of
> those cases.
For the purposes of the above statement, I am considering any complex
type a form of MRV. You'll note that I did state that std::expected
should help significantly.
> Most of the rest are either things like `stoi` where it's returning extra=
=20
> information
Exactly.
> Second, do we want language features like this for "corner cases?" How ma=
ny=20
> such corner cases do you encounter?
We *already have* a language feature. We have a prohibition on defining
types in certain contexts. If IRTVPDUA is accepted, there will be little
reason for that prohibition. This isn't *adding* a feature for corner
cases, it's *removing* a corner case in the specification. In a strict
reading of the standard, that's a *simplification*. It may well be a
simplification in compilers, also. We've already seen that the
limitation is not uniformly enforced, which suggests that at the
compiler implementation level, it may well be artificial. If so,
removing it would also simplify those compilers in which the limitation
is artificial.
> And do we need such corner case features when we have people practically=
=20
> frothing at the mouth to *abuse* it?
I don't see this.
>> Related, I would guess there are quite some times that the lack of easy=
=20
>> to use MRV's results in people simply doing without (and producing an=20
>> inferior API as a result). This is another key distinction I think needs=
=20
>> to be made... it's not so much that this feature is *required*, as that=
=20
>> it would be *beneficial*. After all, range-based for is not *required*=
=20
>> (we got by many years without it, and in C++11 it can be implemented as=
=20
>> a macro), but it's obviously *beneficial*.
>=20
> Agreed but... that doesn't explain why we specifically need *unnamed*=20
> structs to fill that gap.
What else will fill it? If named structs could do so, why don't we see
that already?
> There are two major problems with using `tuple` to fill that gap.
>=20
> 1) It is *exceedingly* painful for the receiving code to use.
>=20
> 2) It provides no useful semantic information beyond the typenames.
>=20
> Structured binding solves problem #1. But it also solves most of problem=
=20
> #2, at least from the perspective of someone reading the receiving code.
....but it doesn't help someone that needs to *write* said code.
> So the space for this feature seems decidedly small. It must be a one-off=
=20
> usage where typenames aren't enough to deduce the meaning.
....and the cost is also small. It involves the removal of a whole two
words from the standard=C2=B9. It removes a corner case of a language featu=
re
that is valid in many contexts being unnecessarily prohibited in a
particular context. It potentially simplifies compilers by removing the
need for them to implement an artificial restriction.
(=C2=B9 And I'll reiterate that I am assuming adoption of IRTVPDUA. To be
even more clear, if IRTVPDUA is *not* adopted, I have no intention of
pressing for relaxing [dcl.fct]/11 without IRTVPDUA.)
>> In virtually every case, what the multiple values meant was readily=20
>>> apparent; there was no need to give each one a semantic name.=20
>>
>> This is definitely *not* my experience in Python. And, frankly, I'd=20
>> probably tend to use anonymous structs for MRV's (if available) over=20
>> tuples, just on principle (of them being more self-documenting).
>=20
> ... How is it more self-documenting?
>=20
> auto x =3D foo();
>=20
> What is `x`? Is it one value? Twenty? I don't know; I have to go look it =
up.
I'm talking about the function declaration. Sure, 'x' in the above
example does not have an obvious meaning, but that's true no matter how
yo return MRV's.
With a struct, when you use x, e.g. 'x.converted_value', the usage is
much clearer than 'get<0>(x)' or even 'get<int>(x)'. It's also much
clearer from the declaration of 'foo()' what is being returned, compared
to returning e.g. std::tuple.
> Typename x =3D foo();
>=20
> This has less substance, but I at least have two pieces of information I=
=20
> can use to figure out what this means. I have the function name and a typ=
e=20
> name.
If that type name is something like tuple<int, double> or foo_result,
how exactly does that help?
In the latter case you probably need to go look at the definition of
foo_result, which is likely to be exactly as difficult as looking at the
declaration of foo() and seeing that it returns '{ int whole_part;
double fraction_part; }'.
>> And if there was a need, then I returned a Lua table with named fields.=
=20
>>
>> How is that unlike returning an anonymous struct? ;-)
>=20
> Because Lua's not a static language. In Lua, I can do this: `foo(bar())`.=
=20
> If `bar` returned 5 values via positional MRV, `foo` would take those 5=
=20
> values. If `bar` returned a table with named fields, that's what `foo`=20
> would get. So regardless of how I return those MRVs, I have lost none of=
=20
> the expressive power of the language.
But that's not likely to ever work in C++, unless there exists an
overload of foo() that takes an appropriate std::tuple.
BTW, that's not possible in Python. In Python, you would have to write:
foo(*bar())
And as I've stated elsewhere, what is so terrible about writing (in C++):
foo([*]bar())
....? This would further allow (as it does in Python) to "merge" multiple
parameter packs, and clarifies when unpacking is intended, and when a
pack should be passed as a single object. It also works just fine if
bar() returns a struct (anonymous or not). Or a tuple. Or anything
"tuple-like".
> If I return an unnamed struct, I cannot chain calls with it. I must use a=
=20
> named type in that circumstance. So unnamed structs have a restriction to=
=20
> my expressive power which named structs and `tuple`s do not have.
Again, I don't see this as a legitimate argument. How often do you see,
given a function like 'foo(int, double)', that folks are starting to
also always write an overload 'foo(tuple<int, double>)'? (Moreover, I'll
go out on a limb and say that if that ever *does* become prevalent,
we've screwed up majorly.) What about foo() and bar() being in different
libraries; why do you expect that foo() will even *know about* the
library from whence bar() comes, much less take the struct that bar()
returns as an alternative to individual parameters?
The whole point of these directions is to move *away* from being locked
into passing multiple values around as specific types, in favor of being
able to dynamically unpack and repack value collections. (We already
have repacking in the form of aggregate initialization. We're working on
unpacking. P0144 / P0151 should fix one aspect, but IMO we still need
something like '[*]'.)
I think this goes back to your insistence from back when that value
collections be some sort of first class citizen *separate* from any
existing notions of complex types. I just don't see that happening. The
language is moving toward fluid conversion between value collections
implemented as aggregates (or otherwise as traditional complex types),
and I can't say that I've seen anyone else supporting your views.
Incidentally, I (briefly) address exactly this point in the current
version of the IRTVPDUA paper.
> Show me 5 actual methods in the same class which return MRVs that follow=
=20
> the 2 principles that I outlined and you agreed with. That is, tuples wou=
ld=20
> be inappropriate because the typenames are non-indicative of the meaning.=
=20
> And no other code uses that same aggregation of values with that meaning.
Why the same class? I'd need five different names whether or not their
in the same class.
>> Naming things is *hard*. Naming multiple return values is *especially*=
=20
>> hard, and bloats the API unnecessarily.
>=20
> I'm sorry, but I have a problem considering inserting a typename to=20
> constitute "bloat".
It's one more name polluting the name space for a *single use*. It's one
more type that shows up in the documentation (and, potentially, *needs
to be documented*=C2=B2). It's one more type that users can construct, when
doing so may make no sense.
If you disagree, I propose that you assign aliases to the return values
of *every function you write*. It's the exact same principle, differing
in scale, but not in principle.
(=C2=B2 Note that I'm considering it easier to document return values than
types with their members. Because... it usually is.)
>> See also Vicente's response to this point. Remember, we're talking about=
=20
>> the cost of naming *one-off* structures.
>=20
> No, we're talking about the cost of naming one-off structures who's=20
> typenames don't provide sufficient semantic information to know what they=
=20
> mean. That's what you agreed to when you agreed with principle #1.
We're talking about naming one-off structures. As opposed to structures
used many times.
>> [IRTVPDUA stuff...]
> Maybe you've mixed up the threads [...] that's a tangential argument.
Yes, I think you're correct in that spot. Sorry.
>> Structured binding, if anything, makes [returning anonymous=20
>> structs] *more* useful.
>=20
> How?
Because the pain of unpacking the struct into its component values is
removed. Structured binding encourages returning MRV's (I think we agree
on this?). This means that people are more likely to return ad-hoc
complex types. These developers are going to fall into three categories:
1. Folks that can't be bothered to name *anything*. These will use
std::tuple.
2. Folks that are anal about naming. These will use named structs.
3. Folks that will name things *if it's easy*.
Camps 1 and 2 aren't interesting; they're going to do what they do
anyway. Returning anonymous structs is interesting to camp 3 (which, to
be fair, I will note is that camp to which I belong). If the individual
values are hard to name, they will use std::tuple. If naming
*everything* is easy, they may well do so. The trouble spot is in the
case (which I assert is not unusual) where naming the individual values
is easy, but naming the *aggregate* is hard (example: stoi).
Do you prefer std::tuple or an anonymous struct in this case? I know
which I prefer.
> It makes returning unnamed structs less useful because `tuple`
> becomes a legitimate MRV solution, rather than a massive eyesore.
I completely disagree here. IMO, even at the declaration site, tuple is
an eyesore. I would much prefer to use an anonymous struct over a tuple.
At the very least, I strongly disagree that unpacking lessens the value
of anonymous structs as an MRV mechanism.
--=20
Matthew
--=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 https://groups.google.com/a/isocpp.org/group/std-propos=
als/.
.