220 36503 <5a504df3-7632-4035-9f94-7c72f0d094af@isocpp.org> article
Path: news.gmane.org!.POSTED!not-for-mail
From: schreiber.corentin@gmail.com
Newsgroups: gmane.comp.lang.c++.isocpp.proposals
Subject: Re: Re: operator[](...)
Date: Sat, 6 Jan 2018 04:38:50 -0800 (PST)
Lines: 306
Approved: news@gmane.org
Message-ID: <5a504df3-7632-4035-9f94-7c72f0d094af@isocpp.org>
References: <ea8aec36-305c-48ca-aedc-0db120fd8fcc@isocpp.org>
 <8bbeac1f-f698-4e49-9e1f-4cb1ab389b09@isocpp.org>
 <3b13beef-4a63-1315-c11d-07ba04e6f9bd@gmail.com>
 <4d35c71c-cdc0-45de-976e-2f70b20695c0@isocpp.org>
Reply-To: std-proposals@isocpp.org
NNTP-Posting-Host: blaine.gmane.org
Mime-Version: 1.0
Content-Type: multipart/mixed; 
	boundary="----=_Part_8162_1730679515.1515242330539"
X-Trace: blaine.gmane.org 1515242223 30152 195.159.176.226 (6 Jan 2018 12:37:03 GMT)
X-Complaints-To: usenet@blaine.gmane.org
NNTP-Posting-Date: Sat, 6 Jan 2018 12:37:03 +0000 (UTC)
To: ISO C++ Standard - Future Proposals <std-proposals@isocpp.org>
Original-X-From: std-proposals+bncBCQLNPVMQILRBW4GYPJAKGQEKDYP6TA@isocpp.org Sat Jan 06 13:36:59 2018
Return-path: <std-proposals+bncBCQLNPVMQILRBW4GYPJAKGQEKDYP6TA@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-ua0-f199.google.com ([209.85.217.199])
	by blaine.gmane.org with esmtp (Exim 4.84_2)
	(envelope-from <std-proposals+bncBCQLNPVMQILRBW4GYPJAKGQEKDYP6TA@isocpp.org>)
	id 1eXniU-00071m-0L
	for gclcip-std-proposals@m.gmane.org; Sat, 06 Jan 2018 13:36:50 +0100
Original-Received: by mail-ua0-f199.google.com with SMTP id j18sf3801563uag.4
        for <gclcip-std-proposals@m.gmane.org>; Sat, 06 Jan 2018 04:38:53 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=isocpp-org.20150623.gappssmtp.com; s=20150623;
        h=date:from:to:message-id:in-reply-to:references:subject:mime-version
         :x-original-sender:reply-to:precedence:mailing-list:list-id
         :list-post:list-help:list-archive:list-subscribe:list-unsubscribe;
        bh=OlR3faWkE7K53cKKKqXv1RNLF/WDo0qEO/gnzhy/oBk=;
        b=W6mDqd/oYTBO++2jrBd8iHu12TNdLSLv6/a0ZZZ/7K3h4iDZeAL4nhQMnCo3QAYt3Y
         m/KHMg74JsgnOXqKLTwidmsNHzHlQh7hEG990Bu8WHjZPK+QAbKT3JEyVqGFvacokgyR
         L/3yg6fnDAsVpx+cdaje2nkHbhrl9YR4k9lJ/wVPJw7/nSr5mEte4j4vuVMxTZvhGQjL
         4DrMHoyIRp28nDVCuOVQOG/Knc5Tng1xzNusYn0AWQ5AE8tsNFqMqYDjpUFK1xf0cbCV
         GrHvD+v9i4CXJHFASuE/BsurotxMZAE1pVpgDn5pkWxlICgpddJtYojVyIKGy+TZSmKS
         hVbA==
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=20161025;
        h=date:from:to:message-id:in-reply-to:references:subject:mime-version
         :x-original-sender:reply-to:precedence:mailing-list:list-id
         :list-post:list-help:list-archive:list-subscribe:list-unsubscribe;
        bh=OlR3faWkE7K53cKKKqXv1RNLF/WDo0qEO/gnzhy/oBk=;
        b=d4xRU66MEmsvCASlGY6nPNPP/4bdMLauABJ12TTgYAjmh/bkqPmw4hn19T8mEF3aoP
         eqtGZxZULRe1o2HoozN29GiBYcNBhSic0af9KE8brEjXgeu+WT7dD0c/MOGEx81Q8PsQ
         AVC3RNoi999/+BXbCkwj51luvKJlK3b8tpakq6P2oWewfCj1YtXpgxRqm5FkD7UsHoRz
         qdsDyixvqfi5ZRgLySBC/PJOVmCLCAB135LJjFAOL0DvXyNAZ6i32HoNmlnMeUIungtr
         EzEAGVYpLLAZjFNAdTSjZH1aChnIMi6no5C165qQ5lkhLKBX2zXZ+WxK9J0WbteOqq6t
         mEiQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20161025;
        h=x-gm-message-state:date:from:to:message-id:in-reply-to:references
         :subject:mime-version: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=OlR3faWkE7K53cKKKqXv1RNLF/WDo0qEO/gnzhy/oBk=;
        b=rL3prsSuluLiPEjsubxQgQDzuPp7QtupH/IaBjpbtGXl8c+ZVBlhd7NusRIaoQrbzp
         EtSvn4HPKOGO2046VR7WYOKFR66Q614QII9jeRRqPvLgH7uV+HmZ8SFzbNZ26AItwSM9
         Q1ES3oFdhS5CySavppowhts8rcYtXTBvvT1dPMvRul+OrMgq9wa5/mPL2bJkn1HNnion
         9pda/B0OSRJF/hxgCC0NEwFKDh11s75LXVqltG5vh2uM8LVrtwoKtFepXaJLX/7fmL7T
         dZ1Mfc0ejGRJSB3Iwl9q6hogGvs6yQeKAPP+wCFLny5R6R2/scGt6Q7J1CfzHxa2Txgi
         P86Q==
X-Gm-Message-State: AKwxytf5kUYBKGtHA2WIF3lWK3ORAtC+laOcodn6JsK4EBy33WmHuiDD
	o0vd8AwTkwLkSm0CKTxxmvLlhA==
X-Google-Smtp-Source: ACJfBovosjKDAigrJfKINWDcItGZo9+bjg2mnyz2J04IqCicwbc1VYHQ8xN3ikEmySPuHwBJmzpM8g==
X-Received: by 10.31.124.197 with SMTP id x188mr2836326vkc.72.1515242333074;
        Sat, 06 Jan 2018 04:38:53 -0800 (PST)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.31.150.196 with SMTP id y187ls1435302vkd.10.gmail; Sat, 06 Jan
 2018 04:38:51 -0800 (PST)
X-Received: by 10.31.10.199 with SMTP id 190mr592757vkk.3.1515242331301;
        Sat, 06 Jan 2018 04:38:51 -0800 (PST)
In-Reply-To: <4d35c71c-cdc0-45de-976e-2f70b20695c0@isocpp.org>
X-Original-Sender: schreiber.corentin@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:36503
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/36503>

------=_Part_8162_1730679515.1515242330539
Content-Type: multipart/alternative; 
	boundary="----=_Part_8163_120293583.1515242330539"

------=_Part_8163_120293583.1515242330539
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Saturday, November 25, 2017 at 11:24:57 PM UTC+1, Nicol Bolas wrote:
>
>
>
> On Saturday, November 25, 2017 at 4:25:26 PM UTC-5, Jonathan M=C3=BCller =
wrote:
>>
>> On 25.11.2017 22:11, Nicol Bolas wrote:=20
>> > You've essentially undermined your proposal by highlighting a problem=
=20
>> > with most multi-argument `[]` proposals.=20
>> >=20
>> > As it currently stands `output[x, y]` already has a meaning. Namely,=
=20
>> > it's equivalent to `output[y]`; the entire text between the `[]` is=20
>> > taken as a single expression, rather than a list of arguments.=20
>> >=20
>> > So you have to invent a new syntax to make what you want possible.=20
>> > Namely, `output[{x, y}]`.=20
>>
>> What would *technically* work is being more liberal when invoking=20
>> operators:=20
>>
>> `output[x][y]` would look for an `operator[]` for `decltype(output)`=20
>> taking a single argument.=20
>> If none is found, it looks for an `operator[]` on `decltype(output)`=20
>> taking two arguments. Here it will find one and invoke it.
>>
>
> But what if you want both?
>
> A common thing for matrix types is to be able to access a scalar member a=
s=20
> well as being able to access a vector column. `matrix[1]` accesses a colu=
mn=20
> (by reference or by copy); `matrix[1][2]` ought to access a scalar (by=20
> reference).
>
> By using the `{}` syntax, you can get exactly what you want. 1D access=20
> returns a column. 2D access returns a reference to a scalar. And overload=
=20
> resolution tells which is which.
>
> It's really the sane way to go. It even allows you to use UDLs to get row=
=20
> access for column-major matrices:
>
> matrix[1]; //Accesses column.
> matrix[1_row]; //Accesses row.
> matrix[{1, 2}]; //Accesses scalar.
>
> No need for a language solution when aggregate initialization and=20
> structured binding gives us everything we need.
>
=20
I think it is clear that the motivation for allowing multi-argument=20
overloads to operator[] is purely syntactic sugar. One can achieve the same=
=20
thing (almost, see below) with current language constructs, such as:
matrix[{1,2}];
matrix(1,2);
matrix[1][2];

Neither of these constructs are ideal though.=20

The first require an extra pair of curly braces for no apparent good=20
reason, and it gives yet another use for braces that a new user would have=
=20
to get their head around. I understand that this is not truly "another use=
=20
for braces", because it uses already existing C++ mechanisms, but from a=20
functional point of view, users will not want to know if "is this an=20
initializer list? or a constructor call? or a structured binding? or...";=
=20
they will need to remember "use bracket for array indexing, and add braces=
=20
for array multi-indexing". Worse, a new user might even try to see if it=20
compiles without the braces, or simply forget them. And compile it will.=20
Perhaps with a warning from the compiler about an unused statement, but=20
note that there is no possibility for a library solution to warn about this=
=20
error.

The second does not look like an array indexing operation, but like a=20
function call or a constructor. This is the solution that most libraries=20
nowadays adopt (see references below). It is not dangerous as the above,=20
but it is irritating because it does not convey the correct intent. Syntax=
=20
highlighters need to parse the definition of "matrix" to know whether=20
"matrix(1,2)" is a function call or not. As a result, most highlighters I=
=20
have seen treat "matrix(1,2)" as a function call, which is incorrect. Then=
=20
you have "matrix[1]" for sequential element access (i.e., as laid out in=20
memory), and "matrix(1,2)" for structured element access, why the need for=
=20
two separate notations when the concept is the same? It's another cognitive=
=20
burden placed on the user.

The third fixes the issues of the above two, but it also has several=20
drawbacks of its own. First, it is not possible to disentangle cases where=
=20
one wants sequential access (go through the array as it is laid out in=20
memory) and structured access (follow the array's multi-dimensional shape).=
=20
"matrix[1]" represents the second row (or column), not a scalar value. This=
=20
can still be done by going through a proxy class/function, e.g.,=20
"matrix.sequential[1]", so I would say it is not such a big deal. Second,=
=20
"matrix[1][2]" requires splitting the indexing between two function calls,=
=20
and creating a temporary for "matrix[1]". This may or may not imply runtime=
=20
overheads, but certainly will increase compile time and library complexity.=
=20
In case of >2D arrays, it also makes it impossible to spot cases where the=
=20
user forgot to specify the last index (i.e., "matrix[1][2]" instead of=20
"matrix[1][2][3]") at the location of the indexing; the error (if any) will=
=20
happen latter when the user tries to use "matrix[1][2]" as a scalar.

Lastly, all above solutions still do not fix the issue that "matrix[1,2]"=
=20
is currently well defined and most certainly does not do what anyone would=
=20
want it to.

So yes, allowing "matrix[1,2]" as an operator[] overload is a breaking=20
change, but it is my opinion one case where benefits greatly outweigh the=
=20
costs. And this is not a niche case. Data science is becoming an=20
increasingly important discipline nowadays, and I think C++ is lagging=20
behind other languages like python, R, etc, (even though C++ outperforms=20
them all) in part because it lacks such simple things.

If this has to happen in 2025, after we have flagged the comma operator=20
inside brackets as deprecated, so be it...

References:
Blazelib:=20
https://bitbucket.org/blaze-lib/blaze/wiki/Matrix%20Operations#!element-acc=
ess
Eigen: https://eigen.tuxfamily.org/dox/group__TutorialMatrixClass.html
xtensor:=20
https://xtensor.readthedocs.io/en/latest/expression.html#element-access

--=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.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/5a504df3-7632-4035-9f94-7c72f0d094af%40isocpp.or=
g.

------=_Part_8163_120293583.1515242330539
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Saturday, November 25, 2017 at 11:24:57 PM UTC+1, Nicol=
 Bolas wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-le=
ft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">=
<br><br>On Saturday, November 25, 2017 at 4:25:26 PM UTC-5, Jonathan M=C3=
=BCller wrote:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-le=
ft:0.8ex;border-left:1px #ccc solid;padding-left:1ex">On 25.11.2017 22:11, =
Nicol Bolas wrote:
<br>&gt; You&#39;ve essentially undermined your proposal by highlighting a =
problem=20
<br>&gt; with most multi-argument `[]` proposals.
<br>&gt;=20
<br>&gt; As it currently stands `output[x, y]` already has a meaning. Namel=
y,=20
<br>&gt; it&#39;s equivalent to `output[y]`; the entire text between the `[=
]` is=20
<br>&gt; taken as a single expression, rather than a list of arguments.
<br>&gt;=20
<br>&gt; So you have to invent a new syntax to make what you want possible.=
=20
<br>&gt; Namely, `output[{x, y}]`.
<br>
<br>What would *technically* work is being more liberal when invoking opera=
tors:
<br>
<br>`output[x][y]` would look for an `operator[]` for `decltype(output)`=20
<br>taking a single argument.
<br>If none is found, it looks for an `operator[]` on `decltype(output)`=20
<br>taking two arguments. Here it will find one and invoke it.<br></blockqu=
ote><div><br></div><div>But what if you want both?</div><div><br></div><div=
>A common thing for matrix types is to be able to access a scalar member as=
 well as being able to access a vector column. `matrix[1]` accesses a colum=
n (by reference or by copy); `matrix[1][2]` ought to access a scalar (by re=
ference).</div><div><br></div><div>By using the `{}` syntax, you can get ex=
actly what you want. 1D access returns a column. 2D access returns a refere=
nce to a scalar. And overload resolution tells which is which.</div><div><b=
r></div><div>It&#39;s really the sane way to go. It even allows you to use =
UDLs to get row access for column-major matrices:</div><div><br></div><div =
style=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);bo=
rder-style:solid;border-width:1px"><code><div><span style=3D"color:#000">ma=
trix</span><span style=3D"color:#660">[</span><span style=3D"color:#066">1<=
/span><span style=3D"color:#660">];</span><span style=3D"color:#000"> </spa=
n><span style=3D"color:#800">//Accesses column.</span><span style=3D"color:=
#000"><br>matrix</span><span style=3D"color:#660">[</span><span style=3D"co=
lor:#066">1</span><span style=3D"color:#000">_row</span><span style=3D"colo=
r:#660">];</span><span style=3D"color:#000"> </span><span style=3D"color:#8=
00">//Accesses row.</span><span style=3D"color:#000"><br>matrix</span><span=
 style=3D"color:#660">[{</span><span style=3D"color:#066">1</span><span sty=
le=3D"color:#660">,</span><span style=3D"color:#000"> </span><span style=3D=
"color:#066">2</span><span style=3D"color:#660">}];</span><span style=3D"co=
lor:#000"> </span><span style=3D"color:#800">//Accesses scalar.</span></div=
></code></div><div><br></div><div></div>No need for a language solution whe=
n aggregate initialization and structured binding gives us everything we ne=
ed.<br></div></blockquote><div>=C2=A0</div>I think it is clear that the mot=
ivation for allowing multi-argument overloads to operator[] is purely synta=
ctic sugar. One can achieve the same thing (almost, see below) with current=
 language constructs, such as:<br><div style=3D"background-color:rgb(250,25=
0,250);border-color:rgb(187,187,187);border-style:solid;border-width:1px"><=
code><div><span style=3D"color:#000">matrix</span><span style=3D"color:#660=
">[{</span><span style=3D"color:#066">1</span><span style=3D"color:#660">,<=
/span><span style=3D"color:#000"></span><span style=3D"color:#066">2</span>=
<span style=3D"color:#660">}];</span><span style=3D"color:#800"></span></di=
v><div>matrix(1,2);</div><div>matrix[1][2];<br><span style=3D"color:#800"><=
/span></div></code></div><div><br></div>Neither of these constructs are ide=
al though. <br><br>The first require an extra pair of curly braces for no a=
pparent good reason, and it gives yet another use for braces that a new use=
r would have to get their head around. I understand that this is not truly =
&quot;another use for braces&quot;, because it uses already existing C++ me=
chanisms, but from a functional point of view, users will not want to know =
if &quot;is this an initializer list? or a constructor call? or a structure=
d binding? or...&quot;; they will need to remember &quot;use bracket for ar=
ray indexing, and add braces for array multi-indexing&quot;. Worse, a new u=
ser might even try to see if it compiles without the braces, or simply forg=
et them. And compile it will. Perhaps with a warning from the compiler abou=
t an unused statement, but note that there is no possibility for a library =
solution to warn about this error.<br><br>The second does not look like an =
array indexing operation, but like a function call or a constructor. This i=
s the solution that most libraries nowadays adopt (see references below). I=
t is not dangerous as the above, but it is irritating because it does not c=
onvey the correct intent. Syntax highlighters need to parse the definition =
of &quot;matrix&quot; to know whether &quot;matrix(1,2)&quot; is a function=
 call or not. As a result, most highlighters I have seen treat &quot;matrix=
(1,2)&quot; as a function call, which is incorrect. Then you have &quot;mat=
rix[1]&quot; for sequential element access (i.e., as laid out in memory), a=
nd &quot;matrix(1,2)&quot; for structured element access, why the need for =
two separate notations when the concept is the same? It&#39;s another cogni=
tive burden placed on the user.<br><br>The third fixes the issues of the ab=
ove two, but it also has several drawbacks of its own. First, it is not pos=
sible to disentangle cases where one wants sequential access (go through th=
e array as it is laid out in memory) and structured access (follow the arra=
y&#39;s multi-dimensional shape). &quot;matrix[1]&quot; represents the seco=
nd row (or column), not a scalar value. This can still be done by going thr=
ough a proxy class/function, e.g., &quot;matrix.sequential[1]&quot;, so I w=
ould say it is not such a big deal. Second, &quot;matrix[1][2]&quot; requir=
es splitting the indexing between two function calls, and creating a tempor=
ary for &quot;matrix[1]&quot;. This may or may not imply runtime overheads,=
 but certainly will increase compile time and library complexity. In case o=
f &gt;2D arrays, it also makes it impossible to spot cases where the user f=
orgot to specify the last index (i.e., &quot;matrix[1][2]&quot; instead of =
&quot;matrix[1][2][3]&quot;) at the location of the indexing; the error (if=
 any) will happen latter when the user tries to use &quot;matrix[1][2]&quot=
; as a scalar.<br><br>Lastly, all above solutions still do not fix the issu=
e that &quot;matrix[1,2]&quot; is currently well defined and most certainly=
 does not do what anyone would want it to.<br><br>So yes, allowing &quot;ma=
trix[1,2]&quot; as an operator[] overload is a breaking change, but it is m=
y opinion one case where benefits greatly outweigh the costs. And this is n=
ot a niche case. Data science is becoming an increasingly important discipl=
ine nowadays, and I think C++ is lagging behind other languages like python=
, R, etc, (even though C++ outperforms them all) in part because it lacks s=
uch simple things.<br><br>If this has to happen in 2025, after we have flag=
ged the comma operator inside brackets as deprecated, so be it...<br><br>Re=
ferences:<br>Blazelib: https://bitbucket.org/blaze-lib/blaze/wiki/Matrix%20=
Operations#!element-access<br>Eigen: https://eigen.tuxfamily.org/dox/group_=
_TutorialMatrixClass.html<br>xtensor: https://xtensor.readthedocs.io/en/lat=
est/expression.html#element-access<br></div>

<p></p>

-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/5a504df3-7632-4035-9f94-7c72f0d094af%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/5a504df3-7632-4035-9f94-7c72f0d094af=
%40isocpp.org</a>.<br />

------=_Part_8163_120293583.1515242330539--

------=_Part_8162_1730679515.1515242330539--

.
