220 24435 <586249ad-b4ae-4e40-bdf7-344a641ad4c9@isocpp.org> article
Path: news.gmane.org!not-for-mail
From: Nicol Bolas <jmckesson@gmail.com>
Newsgroups: gmane.comp.lang.c++.isocpp.proposals
Subject: Re: [tuple] extracting tuples out of a tuple
Date: Tue, 16 Feb 2016 19:28:32 -0800 (PST)
Lines: 567
Approved: news@gmane.org
Message-ID: <586249ad-b4ae-4e40-bdf7-344a641ad4c9@isocpp.org>
References: <CA+wfc1-FFqOJ9OSme_SpJAmGz+cshbMDVi_dLrF1ztbzkTN-WQ@mail.gmail.com>	<n9ksdc$4so$1@ger.gmane.org>	<CA+wfc18LVMDXhRYhkw0PxeOmPiOoqVteF7V+40EdOOYb2K1snA@mail.gmail.com>	<n9l3ns$33l$1@ger.gmane.org>	<7e08b6c5-853c-471e-b248-a9df7e8e27be@isocpp.org>	<n9sscb$n29$1@ger.gmane.org> <CADvuK0La9zc5NKhuzbO0awHWGyonM-P8mT26Jn8v94==P4A=KA@mail.gmail.com> <n9tgki$v5n$1@ger.gmane.org> <67c3c86d-3089-4f07-878a-3f3e706744df@isocpp.org> <42a29c5b-07e4-4e36-bab4-03a7e86ff905@isocpp.org>
 <n9vhfe$jb0$1@ger.gmane.org>
 <6e02dbfe-01f3-4840-92ab-bcc8f7824348@isocpp.org>
 <e8e9e9bc-e810-4300-ad88-d3696a1496b8@isocpp.org>
 <d5279da3-6b47-4cc3-bc13-5c668a8c9e78@isocpp.org>
Reply-To: std-proposals@isocpp.org
NNTP-Posting-Host: plane.gmane.org
Mime-Version: 1.0
Content-Type: multipart/mixed; 
	boundary="----=_Part_7760_750743506.1455679712664"
X-Trace: ger.gmane.org 1455679721 32743 80.91.229.3 (17 Feb 2016 03:28:41 GMT)
X-Complaints-To: usenet@ger.gmane.org
NNTP-Posting-Date: Wed, 17 Feb 2016 03:28:41 +0000 (UTC)
Cc: mwoehlke.floss@gmail.com
To: ISO C++ Standard - Future Proposals <std-proposals@isocpp.org>
Original-X-From: std-proposals+bncBCEKFTV6ZUMBBYWRR63AKGQEAZLHS3A@isocpp.org Wed Feb 17 04:28:36 2016
Return-path: <std-proposals+bncBCEKFTV6ZUMBBYWRR63AKGQEAZLHS3A@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-ig0-f198.google.com ([209.85.213.198])
	by plane.gmane.org with esmtp (Exim 4.69)
	(envelope-from <std-proposals+bncBCEKFTV6ZUMBBYWRR63AKGQEAZLHS3A@isocpp.org>)
	id 1aVsn5-0004t3-Sx
	for gclcip-std-proposals@m.gmane.org; Wed, 17 Feb 2016 04:28:36 +0100
Original-Received: by mail-ig0-f198.google.com with SMTP id rx16sf20940471igc.3
        for <gclcip-std-proposals@m.gmane.org>; Tue, 16 Feb 2016 19:28:35 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=isocpp-org.20150623.gappssmtp.com; s=20150623;
        h=date:from:to:cc:message-id:in-reply-to:references:subject
         :mime-version:content-type:x-original-sender:reply-to:precedence
         :mailing-list:list-id:x-spam-checked-in-group:list-post:list-help
         :list-archive:list-subscribe:list-unsubscribe;
        bh=fOS1J2x3GBFLrQxceI40M5wVUS5urkJb1GJXTRLnBCo=;
        b=hwHZZEAZhfJQVXfQ6MZmzHePuht7r38M6UXuHuhJVpU0pLejkugFb8pNn3hnAfEjOl
         IUF2g3qbde5rxHjqSJBGXK4jKuGvSfg1hcGHR0WJ4e1OzT1XRqjA4jU7yeBoYBudFgRJ
         HOBpSpaj694TdFkrHMTO8lhtHgwbCpFFpKjbomLPkjSopzfLFJzyP+4weDEGE5bE9PkK
         ml9AiW2muhqeoeRVzGpOEAogXI6fo66TGqB0cgeiZ3VNxEzYg+UrnUTtJ2uBvl4aDzdO
         yUD8bUS1/kOpVAp2Wj94SCs2F6vaaXJN5OkkQy6zGDm6QJLTdcu7/sM2WXiJgNWX4HS8
         7LJQ==
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=20120113;
        h=date:from:to:cc:message-id:in-reply-to:references:subject
         :mime-version:content-type:x-original-sender:reply-to:precedence
         :mailing-list:list-id:x-spam-checked-in-group:list-post:list-help
         :list-archive:list-subscribe:list-unsubscribe;
        bh=fOS1J2x3GBFLrQxceI40M5wVUS5urkJb1GJXTRLnBCo=;
        b=rzC+Eu11ESwbOhaUYFrdzEU6cXKaNST8dVo91E/DpCBytUVs3/yWl3rnElbAx8Y5oY
         WxZxcp0ysxu5S+uTXhf611schKqno1BNaoxI7cOxyYLKWklhdC8yLXDx/NDtna3Kp+fg
         nDnkOraxS/3o8RvhS67tfuBtN3Xzzyd3dyxcxaD8abXiVvxSjpStq8PCNWbqs6s9QZpy
         t2JiGcq0RFF+gMpFe+I6ygEf0wWbcO48DqVFXFMHMhotW6uTp3bNXbAI19YCjclwthmO
         h3Ao+fE5lYPmgzfI5OJJ/2W5lFLUCXYkQ7Lz9hYSLzq08eEP/nTuLkdqxd99/N0tcfQ8
         GBww==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20130820;
        h=x-gm-message-state:date:from:to:cc:message-id:in-reply-to
         :references:subject:mime-version:content-type:x-original-sender
         :reply-to:precedence:mailing-list:list-id:x-spam-checked-in-group
         :list-post:list-help:list-archive:list-subscribe:list-unsubscribe;
        bh=fOS1J2x3GBFLrQxceI40M5wVUS5urkJb1GJXTRLnBCo=;
        b=nHN9O4lsK6UheNPT/0kP4Dbpci01nMqOcbRRuTdy+ky1RwmxbtM3DQfLbxLH4w52ZQ
         88oYckfHvK66RMHbaicATMdFLjmifZyWCgAXnOJx8vVsNH6TAvJPVAvWOsPTc47nifAg
         6NovmAezGP33BraXZsa67/VmtlIwvXOsKwd4NF3hYaLga7WfjCQYyaNWQQg1cQvqLlLE
         4VYqW+mzpxfC8frnUZqXe4VWwuZYPbr2mX4Jt+zlaQwvQdhZiLxwJ4aElS3jkNMdJw9H
         MX+9r9J5Hb13EuTmB48kK23zfdgY0PdXE5SPaSqBnmBIs24he/dvpkR3Ac2IJ4OI/afW
         E35Q==
X-Gm-Message-State: AG10YOQmxtUwETShjq3ZxqKbQ3ErbxBz/6eZ9Hte2g/HsOCY1YM40OXj4puQmFzRfq9nEw==
X-Received: by 10.107.157.9 with SMTP id g9mr833591ioe.26.1455679714904;
        Tue, 16 Feb 2016 19:28:34 -0800 (PST)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.107.47.25 with SMTP id j25ls1386034ioo.59.gmail; Tue, 16 Feb
 2016 19:28:34 -0800 (PST)
X-Received: by 10.50.66.236 with SMTP id i12mr5294igt.7.1455679714075;
        Tue, 16 Feb 2016 19:28:34 -0800 (PST)
In-Reply-To: <d5279da3-6b47-4cc3-bc13-5c668a8c9e78@isocpp.org>
X-Original-Sender: jmckesson@gmail.com
Precedence: list
Mailing-list: list std-proposals@isocpp.org; contact std-proposals+owners@isocpp.org
List-ID: <std-proposals.isocpp.org>
X-Spam-Checked-In-Group: std-proposals@isocpp.org
X-Google-Group-Id: 399137483710
List-Post: <https://groups.google.com/a/isocpp.org/group/std-proposals/post>, <mailto:std-proposals@isocpp.org>
List-Help: <https://support.google.com/a/isocpp.org/bin/topic.py?topic=25838>, <mailto:std-proposals+help@isocpp.org>
List-Archive: <https://groups.google.com/a/isocpp.org/group/std-proposals/>
List-Subscribe: <https://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>,
 <mailto:std-proposals+subscribe@isocpp.org>
List-Unsubscribe: <mailto:googlegroups-manage+399137483710+unsubscribe@googlegroups.com>,
 <https://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>
Xref: news.gmane.org gmane.comp.lang.c++.isocpp.proposals:24435
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/24435>

------=_Part_7760_750743506.1455679712664
Content-Type: multipart/alternative; 
	boundary="----=_Part_7761_1482735312.1455679712665"

------=_Part_7761_1482735312.1455679712665
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

On Tuesday, February 16, 2016 at 6:57:59 PM UTC-5, Louis Dionne wrote:
>
> On Tuesday, 16 February 2016 18:19:00 UTC-5, Nicol Bolas wrote:
>>
>> On Tuesday, February 16, 2016 at 3:21:29 PM UTC-5, Louis Dionne wrote:
>>>
>>> or you could also write
>>>
>>>     hana::unpack(tpl, [](auto ...x) { return outer(inner(x)...); });
>>>
>>
>> Whenever your library equivalent to a 1-liner language feature includes=
=20
>> "introduce a Lambda", you have *lost* in terms of code=20
>> comprehensibility. On the other hand, it does fix (most) of the=20
>> functionality problems outlined above.
>>
>
> You're drawing an arbitrary line without any argument for this.
>

.... yes. Code quality is always arbitrary. Some people claim that this is a=
=20
good, easy-to-understand piece of code:

char * strcpy(char *strDest, const char *strSrc)
{
    assert(strDest!=3DNULL && strSrc!=3DNULL);
    char *temp =3D strDest;
    while(*strDest++ =3D *strSrc++);
    return temp;
}

Everyone has their own tastes. But... Concepts TS has 3 different and=20
increasingly brief syntaxes for declaring a constrained template for a=20
reason. In N3701, Stroustrup et. al. defended this by saying:

> Do not confuse the familiar with the simple. The proposed syntax is=20
readable and parsable. We considered =E2=80=9Clouder=E2=80=9D, more verbose=
 notations, but=20
did not find them consistently better than what is described here.

Brevity has value.

Actually,
> I tend to prefer writing things more explicitly like above than using
> nested ... expansions when things get complex, for I think the different
> rules for ... expansion can be confusing.
>

Welcome to the point of the whole idea.

In this example, what we're trying to do is to call `inner` for each=20
element of the tuple, then pass the results as parameters to `outer`. To=20
you, this is something that "gets complex".

The purpose of the language feature is so that it *isn't complex* anymore.=
=20
By making it a language feature, we take something that was "complex" and=
=20
make it simple. That's the point.

Your library solution is much like `std::enable_if`. Yes, it gives you a=20
consistent tool for invoking SFINAE. But I *bet* you'd rather be using=20
Concepts.

`enable_if` makes SFINAE doable, but it requires that you express your=20
condition in an unnatural way. Concepts makes SFINAE *trivial*. Same here:=
=20
Hana makes tuple manipulation doable, but requires that you write your code=
=20
in unnatural ways.

The principle difference is that there's nothing `enable_if` can do that=20
concepts can't. Whereas there's a lot that Hana can do which tuple=20
expansion can't. But that alone doesn't mean that it isn't worth being a=20
language feature.

Lambdas were supposed to obsolete std::bind too. Yet there are still some=
=20
valid uses for it.

But here's the #1 reason why the library solution is the wrong solution:=20
>> you *wrote it wrong*. You forgot to `std::forward` your arguments. And=
=20
>> you forgot to use `decltype(auto)` for the return value. Both of which a=
re=20
>> needed to be exactly equivalent to the above code. Without the=20
>> `decltype(auto)`, if `outer` returned a reference of some kind, it could=
=20
>> provoke an unwanted copy.
>>
>> So it really needed to be:
>>
>> hana::unpack(tpl, [](auto ...x) -> decltype(auto) { return outer(inner(
>> std::forward<decltype(auto)>(x)...)); });
>>
>> I fail to see how this could be considered anywhere nearly as easy to=20
>> understand.
>>
>
> Fair enough. But if we're going to be pedantic, let's be pedantic for=20
> real. What you wanted
> to write is
> hana::unpack(tpl, [](auto&& ...x) -> decltype(auto) { return outer(inner(
> std::forward<decltype(x)>(x))...); });
>
> With this out of the way, I will argue that you actually don't need to=20
> write the above, except
> in rare cases where the tuple is potentially a rvalue. Instead, in most=
=20
> cases, you'd just
> have to write
>
> hana::unpack(tpl, [](auto& ...x) -> decltype(auto) { return outer(inner(x
> )...); });
>
> which is slightly less verbose.
>

My point was not just that it was verbose. My point is that it is both=20
verbose *and* easy to get wrong, which we both demonstrated (though at=20
least my error would have shown up in the compiler ;) ).

Basically, `unpack` is just `std::apply` but with the arguments reversed.
>>>
>>>
>>> > Show me the Hana code for this:
>>> >
>>> > auto x =3D inner([:]tpl) + ...;
>>> >
>>> > This simply calls a function on each element of the tuple and takes=
=20
>>> the sum
>>> > of the results. Again, it works like parameter packs, so it reuses=20
>>> existing
>>> > knowledge.
>>>
>>> You could write
>>>
>>>     auto x =3D hana::fold_left(hana::transform(tpl, inner), std::plus<>=
{});
>>>
>>
>> And for people who natively read right to left, this would probably be=
=20
>> decent. But that's not how the rest of C++ works.
>>
>
> Wtf? How is this different from writing=20
>
> auto x =3D ranges::accumulate(ranges::transformed(...), std::plus<>{});
>
>
You will never catch me writing *that* either.

or equivalently
>>>
>>>     auto x =3D hana::fold_left(tpl, [](auto a, auto b) {
>>>         return a + inner(b);
>>>     });
>>>
>>
>> Again you forgot to forward the arguments and return values properly. No=
t=20
>> to mention, you turn a simple one-liner into a multi-line statement.
>>
>
> Same argument as above. And the fact that I broke the statements into=20
> multiple
> lines to make it more readable is a feature. Honestly, I think this (and=
=20
> especially
> the transform/fold_left variant) is more readable than the variant with=
=20
> ... expansions.
> Of course, your version is more terse, but too terse is not good either.
>

It's not really that it's terse; that's not what attracts me to tuple=20
expansion. What matters most to me is that the code looks as much like=20
normal code ought to look.

This is also what repels me from your ranges example.

Most programmers know what `outer(inner(value))` does. They can understand=
=20
that by inspection, and its meaning is clear. Most programmers understand=
=20
what `inner(value) + inner(value2)` means.

Hana code is not obvious, not to someone who isn't familiar with template=
=20
metaprogramming and such techniques.

While an unsuspecting programmer may not understand exactly what the `...`=
=20
and `[:]` parts mean, they can still look at `outer(inner([:]value)...)`=20
and see that `inner` will be called, followed by `outer`. It carries the=20
same physical structure and code layout of the simple and obvious case. It=
=20
may be more complex under the hood, but the user is not exposed to it.

When looking at `hana::on(inner, outer)`, they have absolutely no idea what=
=20
that means. Not without looking up the docs. There is no intuitive grasp of=
=20
what's going on.

So the value is more than "just" terseness. The value is that the code's=20
structure remains intact. You're not exchanging a call to `+` with=20
`std::plus<>`. You're not altering the overall order and nature of the code=
..

Let's stop arguing over petty details. You want to hear it? Of course your=
=20
> solution
> is better for those use cases, because it was designed with those in mind=
!
> But it is also much more limited, and the point I'm trying to make is tha=
t=20
> from
> the point of view of a metaprogramming library writer, this proposal, in=
=20
> its
> current form, misses the goal just like fold expressions did.
>

And my overall point is that what you want was *never* the goal to begin=20
with. You are denigrating a proposal for not solving a problem that it was=
=20
never intended to solve. The problem it is solving is making tuples work=20
like parameter pack expansion, so as to be able to more effectively access=
=20
data out of tuples in useful ways.

Arbitrary tuple transformations was never the goal. That's a legitimate and=
=20
useful problem domain. But that's not what this is intended to handle. The=
=20
fact that this syntax can indeed handle some of that via clever usage of=20
the syntax is merely a fortunate coincidence.

C++11 already has a construct that is tuple-like in its nature: parameter=
=20
packs. We're just expanding it to work with actual tuples.

--=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_7761_1482735312.1455679712665
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Tuesday, February 16, 2016 at 6:57:59 PM UTC-5, Louis D=
ionne wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-lef=
t: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">O=
n Tuesday, 16 February 2016 18:19:00 UTC-5, Nicol Bolas  wrote:<blockquote =
class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #=
ccc solid;padding-left:1ex"><div dir=3D"ltr">On Tuesday, February 16, 2016 =
at 3:21:29 PM UTC-5, Louis Dionne wrote:<blockquote class=3D"gmail_quote" s=
tyle=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:=
1ex"><div></div></blockquote></div></blockquote></div></blockquote><blockqu=
ote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left=
: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div></div><blockquot=
e class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px=
 #ccc solid;padding-left:1ex"><div dir=3D"ltr"><blockquote class=3D"gmail_q=
uote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;paddin=
g-left:1ex"><div dir=3D"ltr"><div>or you could also write</div><div><br></d=
iv><div>=C2=A0 =C2=A0 hana::unpack(tpl, [](auto ...x) { return outer(inner(=
x)...); });</div></div></blockquote><div><br>Whenever your library equivale=
nt to a 1-liner language feature includes &quot;introduce a Lambda&quot;, y=
ou have <i>lost</i> in terms of code comprehensibility. On the other hand, =
it does fix (most) of the functionality problems outlined above.<br></div><=
/div></blockquote><div><br></div><div>You&#39;re drawing an arbitrary line =
without any argument for this.</div></div></blockquote><div><br>... yes. Co=
de quality is always arbitrary. Some people claim that this is a good, easy=
-to-understand piece of code:<br><br><div class=3D"prettyprint" style=3D"ba=
ckground-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); borde=
r-style: solid; border-width: 1px; word-wrap: break-word;"><code class=3D"p=
rettyprint"><div class=3D"subprettyprint"><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">char</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">*</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> strcpy</span><span style=3D"color: #660;" 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"styled-by-prettify"> </span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">*</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify">strDest</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">const</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-prett=
ify">char</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">*</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify">strSrc</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;" c=
lass=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </span><span style=3D"color: =
#008;" class=3D"styled-by-prettify">assert</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">strDest</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">!=3D</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify">NULL </span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">&amp;&amp;</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> strSrc</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">!=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
>NULL</span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =
=C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by-prettify">cha=
r</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">*</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify">temp </span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> strDest</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </span><span style=3D"color: #00=
8;" class=3D"styled-by-prettify">while</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">(*</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify">strDest</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">++</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">*</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify">strSrc</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">++);</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </span><span sty=
le=3D"color: #008;" class=3D"styled-by-prettify">return</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> temp</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">;</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">}</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"><br></span></div></code></div><br>Everyone has their own =
tastes. But... Concepts TS has 3 different and increasingly brief syntaxes =
for declaring a constrained template for a reason. In N3701, Stroustrup et.=
 al. defended this by saying:<br><br>&gt; Do not confuse the familiar with =
the simple. The proposed syntax is readable and parsable. We considered =E2=
=80=9Clouder=E2=80=9D, more verbose notations, but did not find them consis=
tently better than what is described here.<br><br>Brevity has value.<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 dir=3D"ltr"><div>A=
ctually,</div><div>I tend to prefer writing things more explicitly like abo=
ve than using</div><div>nested ... expansions when things get complex, for =
I think the different</div><div>rules for ... expansion can be confusing.</=
div></div></blockquote><div><br>Welcome to the point of the whole idea.<br>=
<br>In this example, what we&#39;re trying to do is to call `inner` for eac=
h element of the tuple, then pass the results as parameters to `outer`. To =
you, this is something that &quot;gets complex&quot;.<br><br>The purpose of=
 the language feature is so that it <i>isn&#39;t complex</i> anymore. By ma=
king it a language feature, we take something that was &quot;complex&quot; =
and make it simple. That&#39;s the point.<br><br>Your library solution is m=
uch like `std::enable_if`. Yes, it gives you a consistent tool for invoking=
 SFINAE. But I <i>bet</i> you&#39;d rather be using Concepts.<br><br>`enabl=
e_if` makes SFINAE doable, but it requires that you express your condition =
in an unnatural way. Concepts makes SFINAE <i>trivial</i>. Same here: Hana =
makes tuple manipulation doable, but requires that you write your code in u=
nnatural ways.<br><br>The principle difference is that there&#39;s nothing =
`enable_if` can do that concepts can&#39;t. Whereas there&#39;s a lot that =
Hana can do which tuple expansion can&#39;t. But that alone doesn&#39;t mea=
n that it isn&#39;t worth being a language feature.<br><br>Lambdas were sup=
posed to obsolete std::bind too. Yet there are still some valid uses for 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;"><div dir=3D"ltr=
"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;bor=
der-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>But here&#3=
9;s the #1 reason why the library solution is the wrong solution: you <i>wr=
ote it wrong</i>. You forgot to `std::forward` your arguments. And you forg=
ot to use `decltype(auto)` for the return value. Both of which are needed t=
o be exactly equivalent to the above code. Without the `decltype(auto)`, if=
 `outer` returned a reference of some kind, it could provoke an unwanted co=
py.<br><br>So it really needed to be:<br><br><div style=3D"background-color=
:rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;border-w=
idth:1px;word-wrap:break-word"><code><div><span style=3D"color:#000">hana</=
span><span style=3D"color:#660">::</span><span style=3D"color:#000">unpack<=
/span><span style=3D"color:#660">(</span><span style=3D"color:#000">tpl</sp=
an><span style=3D"color:#660">,</span><span style=3D"color:#000"> </span><s=
pan style=3D"color:#660">[](</span><span style=3D"color:#008">auto</span><s=
pan style=3D"color:#000"> </span><span style=3D"color:#660">...</span><span=
 style=3D"color:#000">x</span><span style=3D"color:#660">)</span><span styl=
e=3D"color:#000"> </span><span style=3D"color:#660">-&gt;</span><span style=
=3D"color:#000"> </span><span style=3D"color:#008">decltype</span><span sty=
le=3D"color:#660">(</span><span style=3D"color:#008">auto</span><span style=
=3D"color:#660">)</span><span style=3D"color:#000"> </span><span style=3D"c=
olor:#660">{</span><span style=3D"color:#000"> </span><span style=3D"color:=
#008">return</span><span style=3D"color:#000"> outer</span><span style=3D"c=
olor:#660">(</span><span style=3D"color:#000">inner</span><span style=3D"co=
lor:#660">(</span><span style=3D"color:#000">std</span><span style=3D"color=
:#660">::</span><span style=3D"color:#000">forward</span><span style=3D"col=
or:#660">&lt;</span><span style=3D"color:#008">declt<wbr>ype</span><span st=
yle=3D"color:#660">(</span><span style=3D"color:#008">auto</span><span styl=
e=3D"color:#660">)&gt;(</span><span style=3D"color:#000">x</span><span styl=
e=3D"color:#660">)...));</span><span style=3D"color:#000"> </span><span sty=
le=3D"color:#660">});</span></div></code></div><br>I fail to see how this c=
ould be considered anywhere nearly as easy to understand.<br></div></div></=
blockquote><div><br></div><div>Fair enough. But if we&#39;re going to be pe=
dantic, let&#39;s be pedantic for real. What you wanted</div><div>to write =
is</div><div><div style=3D"background-color:rgb(250,250,250);border:1px sol=
id rgb(187,187,187);word-wrap:break-word"><code><div><span style=3D"color:#=
000">hana</span><span style=3D"color:#660">::</span><span style=3D"color:#0=
00">unpack</span><span style=3D"color:#660">(</span><span style=3D"color:#0=
00">tpl</span><span style=3D"color:#660">,</span><span style=3D"color:#000"=
> </span><span style=3D"color:#660">[](</span><span style=3D"color:#008">au=
to</span><span style=3D"color:#660">&amp;&amp;</span><span style=3D"color:#=
000"> </span><span style=3D"color:#660">...</span><span style=3D"color:#000=
">x</span><span style=3D"color:#660">)</span><span style=3D"color:#000"> </=
span><font color=3D"#666600"><span style=3D"color:#660">-&gt;</span><span s=
tyle=3D"color:#000"> </span><span style=3D"color:#008">decltype</span><span=
 style=3D"color:#660">(</span><span style=3D"color:#008">auto</span><span s=
tyle=3D"color:#660">)</span><span style=3D"color:#000"> </span><span style=
=3D"color:#660">{</span><span style=3D"color:#000"> </span><span style=3D"c=
olor:#008">return</span><span style=3D"color:#000"> outer</span><span style=
=3D"color:#660">(</span><span style=3D"color:#000">inner</span><span style=
=3D"color:#660">(</span><span style=3D"color:#000">std</span><span style=3D=
"color:#660">::</span><span style=3D"color:#000">forward</span><span style=
=3D"color:#660">&lt;</span><span style=3D"color:#008">declt<wbr>ype</span><=
span style=3D"color:#660">(</span><span style=3D"color:#000">x</span><span =
style=3D"color:#660">)&gt;(</span><span style=3D"color:#000">x</span><span =
style=3D"color:#660">))...);</span><span style=3D"color:#000"> </span><span=
 style=3D"color:#660">});</span></font></div></code></div><div><br></div><d=
iv>With this out of the way, I will argue that you actually don&#39;t need =
to write the above, except</div><div>in rare cases where the tuple is poten=
tially a rvalue. Instead, in most cases, you&#39;d just</div><div>have to w=
rite</div><div><br></div><div><div style=3D"background-color:rgb(250,250,25=
0);border:1px solid rgb(187,187,187);word-wrap:break-word"><code><div><font=
 color=3D"#660066"><span style=3D"color:#000">hana</span><span style=3D"col=
or:#660">::</span><span style=3D"color:#000">unpack</span><span style=3D"co=
lor:#660">(</span><span style=3D"color:#000">tpl</span><span style=3D"color=
:#660">,</span><span style=3D"color:#000"> </span><span style=3D"color:#660=
">[](</span><span style=3D"color:#008">auto</span><span style=3D"color:#660=
">&amp;</span><span style=3D"color:#000"> </span><span style=3D"color:#660"=
>...</span><span style=3D"color:#000">x</span><span style=3D"color:#660">)<=
/span><span style=3D"color:#000"> </span><span style=3D"color:#660">-&gt;</=
span><span style=3D"color:#000"> </span><span style=3D"color:#008">decltype=
</span><span style=3D"color:#660">(</span><span style=3D"color:#008">auto</=
span><span style=3D"color:#660">)</span><span style=3D"color:#000"> </span>=
<span style=3D"color:#660">{</span><span style=3D"color:#000"> </span><span=
 style=3D"color:#008">return</span><span style=3D"color:#000"> outer</span>=
<span style=3D"color:#660">(</span><span style=3D"color:#000">inner</span><=
span style=3D"color:#660">(</span><span style=3D"color:#000">x</span><span =
style=3D"color:#660">)...);</span><span style=3D"color:#000"> </span><span =
style=3D"color:#660">});</span></font></div></code></div><div><br></div>whi=
ch is slightly less verbose.</div></div></div></blockquote><div><br>My poin=
t was not just that it was verbose. My point is that it is both verbose <i>=
and</i> easy to get wrong, which we both demonstrated (though at least my e=
rror would have shown up in the compiler ;) ).<br><br></div><blockquote cla=
ss=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #=
ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><div></div></div><block=
quote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left=
:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div></div><blockquote c=
lass=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #c=
cc solid;padding-left:1ex"><div dir=3D"ltr"><div></div><div>Basically, `unp=
ack` is just `std::apply` but with the arguments reversed.</div><div><br></=
div><div><br></div><div>&gt; Show me the Hana code for this:</div><div>&gt;=
</div><div>&gt; auto x =3D inner([:]tpl) + ...;</div><div>&gt;</div><div>&g=
t; This simply calls a function on each element of the tuple and takes the =
sum</div><div>&gt; of the results. Again, it works like parameter packs, so=
 it reuses existing</div><div>&gt; knowledge.</div><div><br></div><div>You =
could write</div><div><br></div><div>=C2=A0 =C2=A0 auto x =3D hana::fold_le=
ft(hana::<wbr>transform(tpl, inner), std::plus&lt;&gt;{});</div></div></blo=
ckquote><div><br>And for people who natively read right to left, this would=
 probably be decent. But that&#39;s not how the rest of C++ works.<br></div=
></div></blockquote><div><br></div><div>Wtf? How is this different from wri=
ting=C2=A0</div><div><br></div><div><div style=3D"background-color:rgb(250,=
250,250);border:1px solid rgb(187,187,187);word-wrap:break-word"><code><div=
><font color=3D"#000000"><span style=3D"color:#008">auto</span><span style=
=3D"color:#000"> x </span><span style=3D"color:#660">=3D</span><span style=
=3D"color:#000"> ranges</span><span style=3D"color:#660">::</span><span sty=
le=3D"color:#000">accumulate</span><span style=3D"color:#660">(</span></fon=
t><span style=3D"color:#000">ranges</span><span style=3D"color:#660">::</sp=
an><font color=3D"#000000"><span style=3D"color:#000">tra<wbr>nsformed</spa=
n><span style=3D"color:#660">(...)</span></font><font color=3D"#000000"><sp=
an style=3D"color:#660">,</span><span style=3D"color:#000"> std</span><span=
 style=3D"color:#660">::</span><span style=3D"color:#000">plus</span><span =
style=3D"color:#660">&lt;&gt;{});</span></font></div></code></div><div><br>=
</div></div></div></blockquote><div><br>You will never catch me writing <i>=
that</i> either.<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;">=
<div dir=3D"ltr"><div><div></div><div></div></div><blockquote class=3D"gmai=
l_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;pad=
ding-left:1ex"><div dir=3D"ltr"><div></div><blockquote class=3D"gmail_quote=
" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-le=
ft:1ex"><div dir=3D"ltr"><div></div><div>or equivalently</div><div><br></di=
v><div>=C2=A0 =C2=A0 auto x =3D hana::fold_left(tpl, [](auto a, auto b) {</=
div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 return a + inner(b);</div><div>=C2=A0 =
=C2=A0 });</div></div></blockquote><div><br>Again you forgot to forward the=
 arguments and return values properly. Not to mention, you turn a simple on=
e-liner into a multi-line statement.<br></div></div></blockquote><div><br><=
/div><div>Same argument as above. And the fact that I broke the statements =
into multiple</div><div>lines to make it more readable is a feature. Honest=
ly, I think this (and especially</div><div>the transform/fold_left variant)=
 is more readable than the variant with ... expansions.</div><div>Of course=
, your version is more terse, but too terse is not good either.</div></div>=
</blockquote><div><br>It&#39;s not really that it&#39;s terse; that&#39;s n=
ot what attracts me to tuple expansion. What matters most to me is that the=
 code looks as much like normal code ought to look.<br><br>This is also wha=
t repels me from your ranges example.<br><br>Most programmers know what `ou=
ter(inner(value))` does. They can understand that by inspection, and its me=
aning is clear. Most programmers understand what `inner(value) + inner(valu=
e2)` means.<br><br>Hana code is not obvious, not to someone who isn&#39;t f=
amiliar with template metaprogramming and such techniques.<br><br>While an =
unsuspecting programmer may not understand exactly what the `...` and `[:]`=
 parts mean, they can still look at `outer(inner([:]value)...)` and see tha=
t `inner` will be called, followed by `outer`. It carries the same physical=
 structure and code layout of the simple and obvious case. It may be more c=
omplex under the hood, but the user is not exposed to it.<br><br>When looki=
ng at `hana::on(inner, outer)`, they have absolutely no idea what that mean=
s. Not without looking up the docs. There is no intuitive grasp of what&#39=
;s going on.<br><br>So the value is more than &quot;just&quot; terseness. T=
he value is that the code&#39;s structure remains intact. You&#39;re not ex=
changing a call to `+` with `std::plus&lt;&gt;`. You&#39;re not altering th=
e overall order and nature of the code.<br><br></div><blockquote class=3D"g=
mail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc sol=
id;padding-left: 1ex;"><div dir=3D"ltr"><div></div><div>Let&#39;s stop argu=
ing over petty details. You want to hear it? Of course your solution</div><=
div>is better for those use cases, because it was designed with those in mi=
nd!</div><div>But it is also much more limited, and the point I&#39;m tryin=
g to make is that from</div><div>the point of view of a metaprogramming lib=
rary writer, this proposal, in its</div><div>current form, misses the goal =
just like fold expressions did.</div></div></blockquote><div><br>And my ove=
rall point is that what you want was <i>never</i> the goal to begin with. Y=
ou are denigrating a proposal for not solving a problem that it was never i=
ntended to solve. The problem it is solving is making tuples work like para=
meter pack expansion, so as to be able to more effectively access data out =
of tuples in useful ways.<br><br>Arbitrary tuple transformations was never =
the goal. That&#39;s a legitimate and useful problem domain. But that&#39;s=
 not what this is intended to handle. The fact that this syntax can indeed =
handle some of that via clever usage of the syntax is merely a fortunate co=
incidence.<br><br>C++11 already has a construct that is tuple-like in its n=
ature: parameter packs. We&#39;re just expanding it to work with actual tup=
les.<br></div></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"https://groups.google.com/a/isocpp.org/group=
/std-proposals/">https://groups.google.com/a/isocpp.org/group/std-proposals=
/</a>.<br />

------=_Part_7761_1482735312.1455679712665--
------=_Part_7760_750743506.1455679712664--

.
