Topic: Spread operator (...) for aggregate initialization
Author: Jonas Lund <whizzter@gmail.com>
Date: Sun, 11 Nov 2018 13:06:43 -0800 (PST)
Raw View
------=_Part_1665_1628738501.1541970403989
Content-Type: multipart/alternative;
boundary="----=_Part_1666_470787827.1541970403989"
------=_Part_1666_470787827.1541970403989
Content-Type: text/plain; charset="UTF-8"
Rationale:
C++20 designated initialization for objects is a great quality of life
improvement but right now only goes half the way and with small changes
could promote constant usage and improve code quality.
In scenarios where an object copy is made but only a small part of the
members needs updating this could lead to far better code with relatively
small changes.
Example:
Given:
struct vec3 { float x,y,z; };
vec3 oldvec{1,2,3};
You can write (old):
vec3 newvec(oldvec);
newvec.y=20;
C++20 now lets you do:
vec3 newvec{ .x=oldvec.x , .y=20 , .z=oldvec.z };
This proposal would enable:
vec3 newvec{ ...oldvec , .y=20 };
Effort needed to implement:
Should be relatively low effort, no new keywords and C++20 already has
added designated initializers and this should be able to build on that.
Syntax rules:
Within an aggregate initialization while the rest operator (...) is
encountered at the beginning of a list (in the same place a designatede
initializer would be) the ... is expected to be followed by an value that
is the source value to pick members from, the compiler should allow for
multiple source values.
AFTER the last rest operator has been found there can only be additional
designated initializers.
(Putting spreads after designated initializers makes little sense if
following the semantics below)
IE:
T object * {* *.*designator *=* arg1 *,* *.*designator *{* arg2 *} *... *};*
would become
T object * {* ...sarg1, ...sarg2 , <SNIP> *.*designator *=* darg1 *,* *.*
designator *{* darg2 *} *<SNIP> *};*
(<SNIP> is used above since ... would be ambigious in this case)
sarg1, sarg2 are source objects whilst darg1 and darg2 are direct values.
Semantics:
The compiler should expand all members from each source arg(sarg) in
left-to-right order, the expanded members if overridden by other spreads or
explicitly given designated initializers should be ignored.
The spreading should occur on a visible OR public per-name basis, thus a
source-arg need not be of the same type as the object being initialized and
multiple objects of different types can be used to initialize one
destination object.
Spreading a member that does not exist in the destination must not be
allowed.
--
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 email 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/618d7960-6f9e-447d-9020-adc06a67652a%40isocpp.org.
------=_Part_1666_470787827.1541970403989
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div><font size=3D"4">Rationale:</font></div>C++20 designa=
ted initialization for objects is a great quality of life improvement but r=
ight now only goes half the way and with small changes could promote consta=
nt usage and improve code quality.<div><br></div><div>In scenarios where an=
object copy is made but only a small part of the members needs updating th=
is could lead to far better code with relatively small changes.</div><div><=
br></div><div><font size=3D"4">Example:</font></div><div><br></div><div>Giv=
en:</div><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250=
, 250); border-color: rgb(187, 187, 187); border-style: solid; border-width=
: 1px; overflow-wrap: break-word;"><code class=3D"prettyprint"><div class=
=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-prettif=
y">struct</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
vec3 </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: #008;" class=3D"styled-by-prettify">float</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> x</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify">y</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify">z</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">};</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"><br>vec3 oldvec</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span styl=
e=3D"color: #066;" class=3D"styled-by-prettify">1</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #066;"=
class=3D"styled-by-prettify">2</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">,</span><span style=3D"color: #066;" class=3D"styled-b=
y-prettify">3</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">};</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><=
br></span></div></code></div><div><br><br></div><div>You can write (old):</=
div><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250=
); border-color: rgb(187, 187, 187); border-style: solid; border-width: 1px=
; overflow-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"sub=
prettyprint"><span style=3D"color: #000;" class=3D"styled-by-prettify">vec3=
newvec</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify">oldvec</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"><br>newvec</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">.</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify">y</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #066;" cla=
ss=3D"styled-by-prettify">20</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"><br><br></span></div></code></div><div><br><br></div><div>C++20 no=
w lets you do:</div><div class=3D"prettyprint" style=3D"background-color: r=
gb(250, 250, 250); border-color: rgb(187, 187, 187); border-style: solid; b=
order-width: 1px; overflow-wrap: break-word;"><code class=3D"prettyprint"><=
div class=3D"subprettyprint"><span style=3D"color: #000;" class=3D"styled-b=
y-prettify">vec3 newvec</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> </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><span =
style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">oldvec</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">.</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify">x </span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">.</span><span style=3D"color: #000;" class=3D"styled-by-prettify">y=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span>=
<span style=3D"color: #066;" class=3D"styled-by-prettify">20</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"co=
lor: #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: #000;" class=3D"style=
d-by-prettify">z</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify">o=
ldvec</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify">z </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></div></code>=
</div><div><br><br></div><div>This proposal would enable:</div><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; overflow-wra=
p: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><=
span style=3D"color: #000;" class=3D"styled-by-prettify">vec3 newvec</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">...</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify">oldvec </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-b=
y-prettify">.</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y">y</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</s=
pan><span style=3D"color: #066;" class=3D"styled-by-prettify">20</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">};</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"><br><br></span></div></code></div><d=
iv><br><br></div><div><font size=3D"4">Effort needed to implement:</font></=
div><div>Should be relatively low effort, no new keywords and C++20 already=
has added designated initializers and this should be able to build on that=
..</div><div><br></div><div><font size=3D"4">Syntax rules:</font></div><div>=
Within an aggregate initialization while the rest operator (...) is encount=
ered at the beginning of a list (in the same place a designatede initialize=
r would be) the ... is expected to be followed by an value that is the sour=
ce value to pick members from, the compiler should allow for multiple sourc=
e values.</div><div>AFTER the last rest operator has been found there can o=
nly be additional designated initializers.</div><div>(Putting spreads after=
designated initializers makes little sense if following the semantics belo=
w)</div><div><br></div><div>IE:</div><div><span class=3D"t-spar">T</span> <=
span class=3D"t-spar">object</span> <code><b> {</b></code> <code><b>.</b></=
code><span class=3D"t-spar">designator</span> <code><b>=3D</b></code> <span=
class=3D"t-spar">arg1</span> <code><b>,</b></code> <code><b>.</b></code><s=
pan class=3D"t-spar">designator</span> <code><b>{</b></code> <span class=3D=
"t-spar">arg2</span> <code><b>} </b></code>... <code><b>};</b></code><br></=
div><div><br></div><div>would become</div><div><span class=3D"t-spar">T</sp=
an> <span class=3D"t-spar">object</span> <code><b> {</b></code>=C2=A0...sar=
g1, ...sarg2 ,=C2=A0 =C2=A0<SNIP>=C2=A0<code><b>.</b></code><span cla=
ss=3D"t-spar">designator</span> <code><b>=3D</b></code>=C2=A0d<span class=
=3D"t-spar">arg1</span> <code><b>,</b></code> <code><b>.</b></code><span cl=
ass=3D"t-spar">designator</span> <code><b>{</b></code>=C2=A0d<span class=3D=
"t-spar">arg2</span> <code><b>}=C2=A0</b></code><SNIP>=C2=A0<code><b>=
};</b></code></div><div><br></div><div>(<SNIP> is used above since ..=
.. would be ambigious in this case)</div><div>sarg1, sarg2 are source object=
s whilst darg1 and darg2 are direct values.</div><div><br></div><div><font =
size=3D"4">Semantics:</font></div><div>The compiler should expand all membe=
rs from each source arg(sarg) in left-to-right order, the expanded members =
if overridden by other spreads or explicitly given designated initializers =
should be ignored.</div><div>The spreading should occur on a visible OR pub=
lic per-name basis, thus a source-arg need not be of the same type as the o=
bject being initialized and multiple objects of different types can be used=
to initialize one destination object.</div><div>Spreading a member that do=
es not exist in the destination must not be allowed.</div><div><br></div></=
div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/618d7960-6f9e-447d-9020-adc06a67652a%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/618d7960-6f9e-447d-9020-adc06a67652a=
%40isocpp.org</a>.<br />
------=_Part_1666_470787827.1541970403989--
------=_Part_1665_1628738501.1541970403989--
.
Author: Zhihao Yuan <zy@miator.net>
Date: Sun, 11 Nov 2018 21:31:00 +0000
Raw View
This is a multi-part message in MIME format.
--b1_59692d34acc2931683c76176a7c46f37
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
Interesting, but I don't think cross-type, name-based
designated initialization makes sense, thus only one
spreader of the same type should be allowed.
There is another way to look at this. Let's consider
how do we designate initialize an aggregate with
base class:
struct Base { int a, b; };
struct Derived : Base { double c; };
Currently we can only do
Derived{ .c =3D 3.0 }
and Base is initialized with {}. We could treat
Base as a designater instead:
Derived{ .Base {1, 2}, .c =3D 3.0 }
Now if we treat Derived is its own base, we get
Derived{ .Derived{ 1, 2, 2.0 }, .c =3D 3.0 }
and .c =3D 3.0 should override 2.0, which is the
semantics you wanted.
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
_______________________________________________
=E2=80=90=E2=80=90=E2=80=90=E2=80=90=E2=80=90=E2=80=90=E2=80=90 Original Me=
ssage =E2=80=90=E2=80=90=E2=80=90=E2=80=90=E2=80=90=E2=80=90=E2=80=90
On Sunday, November 11, 2018 3:06 PM, Jonas Lund <whizzter@gmail.com> wrote=
:
> Semantics:
> The compiler should expand all members from each source arg(sarg) in left=
-to-right order, the expanded members if overridden by other spreads or exp=
licitly given designated initializers should be ignored.
> The spreading should occur on a visible OR public per-name basis, thus a =
source-arg need not be of the same type as the object being initialized and=
multiple objects of different types can be used to initialize one destinat=
ion object.
> Spreading a member that does not exist in the destination must not be all=
owed.
--=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/G4G3bioHm7a5pEl_MYWMqCr0bRKiUvIhJI7MJ-BfXmt5Mc3q=
F1gvhGv-DQJ4UWdVhnmySQ6-9_EOtxuqWaaWzr-8CDX6anYL55X03BHTQsw%3D%40miator.net=
..
--b1_59692d34acc2931683c76176a7c46f37
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div>Interesting, but I don't think cross-type, name-based<br></div><div>de=
signated initialization makes sense, thus only one<br></div><div>spreader o=
f the same type should be allowed.<br></div><div><br></div><div>There is an=
other way to look at this. Let's consider<br></div><div>how do we des=
ignate initialize an aggregate with<br></div><div>base class:<br></div><div=
><br></div><div> struct Base { int a, b; };<br></div><div> stru=
ct Derived : Base { double c; };<br></div><div><br></div><div>Currently we =
can only do<br></div><div><br></div><div> Derived{ .c =3D 3.0 }<br></=
div><div><br></div><div>and Base is initialized with {}. We could tre=
at<br></div><div>Base as a designater instead:<br></div><div><br></div><div=
> Derived{ .Base {1, 2}, .c =3D 3.0 }<br></div><div><br></div><div>No=
w if we treat Derived is its own base, we get<br></div><div><br></div><div>=
Derived{ .Derived{ 1, 2, 2.0 }, .c =3D 3.0 }<br></div><div><br></div=
><div>and .c =3D 3.0 should override 2.0, which is the<br></div><div>semant=
ics you wanted.<br></div><div><br></div><div class=3D"protonmail_signature_=
block"><div class=3D"protonmail_signature_block-user"><div>--<br></div><div=
><span>Zhihao Yuan, ID lichray<br>The best way to predict the future is to =
invent it.<br>_______________________________________________</span></div><=
/div><div class=3D"protonmail_signature_block-proton protonmail_signature_b=
lock-empty"><br></div></div><div><br></div><div>=E2=80=90=E2=80=90=E2=80=90=
=E2=80=90=E2=80=90=E2=80=90=E2=80=90 Original Message =E2=80=90=E2=80=90=E2=
=80=90=E2=80=90=E2=80=90=E2=80=90=E2=80=90<br></div><div> On Sunday, Novemb=
er 11, 2018 3:06 PM, Jonas Lund <whizzter@gmail.com> wrote:<br></div>=
<div> <br></div><blockquote type=3D"cite" class=3D"protonmail_quote"><div d=
ir=3D"ltr"><div><span style=3D"font-size:18px">Semantics:</span><br></div><=
div>The compiler should expand all members from each source arg(sarg) in le=
ft-to-right order, the expanded members if overridden by other spreads or e=
xplicitly given designated initializers should be ignored.<br></div><div>Th=
e spreading should occur on a visible OR public per-name basis, thus a sour=
ce-arg need not be of the same type as the object being initialized and mul=
tiple objects of different types can be used to initialize one destination =
object.<br></div><div>Spreading a member that does not exist in the destina=
tion must not be allowed.<br></div></div></blockquote><div><br></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/G4G3bioHm7a5pEl_MYWMqCr0bRKiUvIhJI7MJ=
-BfXmt5Mc3qF1gvhGv-DQJ4UWdVhnmySQ6-9_EOtxuqWaaWzr-8CDX6anYL55X03BHTQsw%3D%4=
0miator.net?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/G4G3bioHm7a5pEl_MYWMqCr0bRKiUvIhJI7MJ=
-BfXmt5Mc3qF1gvhGv-DQJ4UWdVhnmySQ6-9_EOtxuqWaaWzr-8CDX6anYL55X03BHTQsw%3D%4=
0miator.net</a>.<br />
--b1_59692d34acc2931683c76176a7c46f37--
.
Author: Jonas Lund <whizzter@gmail.com>
Date: Sun, 11 Nov 2018 14:29:47 -0800 (PST)
Raw View
------=_Part_1670_1447939185.1541975387307
Content-Type: multipart/alternative;
boundary="----=_Part_1671_476583246.1541975387307"
------=_Part_1671_476583246.1541975387307
Content-Type: text/plain; charset="UTF-8"
>
> Interesting, but I don't think cross-type, name-based
> designated initialization makes sense, thus only one
> spreader of the same type should be allowed.
>
Depends on how one views the feature, name based could be useful for Q&D
conversion between libraries with similar types but conversion operators
might be a better fit for that use-case anyhow.
But i agree the potential for errors could possibly another option where to
restrict to same or parent classes as sources for initialization material
(we could spread all parent types with different inputs) and partial
overrides could also be useful (ie spread from the same type first then a
parent type to replace parts of the object).
There is another way to look at this. Let's consider
> how do we designate initialize an aggregate with
> base class:
>
> struct Base { int a, b; };
> struct Derived : Base { double c; };
>
> Currently we can only do
>
> Derived{ .c = 3.0 }
>
> and Base is initialized with {}. We could treat
> Base as a designater instead:
>
> Derived{ .Base {1, 2}, .c = 3.0 }
>
> Now if we treat Derived is its own base, we get
>
> Derived{ .Derived{ 1, 2, 2.0 }, .c = 3.0 }
>
> and .c = 3.0 should override 2.0, which is the
> semantics you wanted.
>
I kinda see the logic in this syntax but i don't think it gives much
benefits.
One would usually provide source-args as values that the compiler can infer
the type from so specifying it again would serve little purpose and the
rest operator ... has a similar semantic meaning in other contexts like
template pack spreading (and other languages also since this syntax would
be very similar to what exists in ES6/TS where it is in widespread usage
already)
--
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 email 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/3f9af11d-9d4f-43ea-8683-6e5b18f267d9%40isocpp.org.
------=_Part_1671_476583246.1541975387307
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div>Interest=
ing, but I don't think cross-type, name-based<br></div><div>designated =
initialization makes sense, thus only one<br></div><div>spreader of the sam=
e type should be allowed.<br></div></blockquote><div><br></div><div>Depends=
on how one views the feature, name based could be useful for Q&D conve=
rsion between libraries with similar types but conversion operators might b=
e a better fit for that use-case anyhow.</div><div>But i agree the potentia=
l for errors could possibly another option where to restrict to same or par=
ent classes as sources for initialization material (we could spread all par=
ent types with different inputs) and partial overrides could also be useful=
(ie spread from the same type first then a parent type to replace parts of=
the object).</div><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>There is another way to look at this.=C2=A0 Let's consider<b=
r></div><div>how do we designate initialize an aggregate with<br></div><div=
>base class:<br></div><div><br></div><div>=C2=A0 struct Base { int a, b; };=
<br></div><div>=C2=A0 struct Derived : Base { double c; };<br></div><div><b=
r></div><div>Currently we can only do<br></div><div><br></div><div>=C2=A0 D=
erived{ .c =3D 3.0 }<br></div><div><br></div><div>and Base is initialized w=
ith {}.=C2=A0 We could treat<br></div><div>Base as a designater instead:<br=
></div><div><br></div><div>=C2=A0 Derived{ .Base {1, 2}, .c =3D 3.0 }<br></=
div><div><br></div><div>Now if we treat Derived is its own base, we get<br>=
</div><div><br></div><div>=C2=A0 Derived{ .Derived{ 1, 2, 2.0 }, .c =3D 3.0=
}<br></div><div><br></div><div>and .c =3D 3.0 should override 2.0, which i=
s the<br></div><div>semantics you wanted.</div></blockquote><div><br></div>=
<div>I kinda see the logic in this syntax but i don't think it gives mu=
ch benefits.</div><div>One would usually provide source-args as values that=
the compiler can infer the type from so specifying it again would serve li=
ttle purpose and the rest operator ... has a similar semantic meaning in ot=
her contexts like template pack spreading (and other languages also since t=
his syntax would be very similar to what exists in ES6/TS where it is in wi=
despread usage already)</div></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/3f9af11d-9d4f-43ea-8683-6e5b18f267d9%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/3f9af11d-9d4f-43ea-8683-6e5b18f267d9=
%40isocpp.org</a>.<br />
------=_Part_1671_476583246.1541975387307--
------=_Part_1670_1447939185.1541975387307--
.
Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
Date: Sun, 11 Nov 2018 18:36:57 -0800 (PST)
Raw View
------=_Part_381_2076920749.1541990217312
Content-Type: multipart/alternative;
boundary="----=_Part_382_810184655.1541990217313"
------=_Part_382_810184655.1541990217313
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
On Sunday, November 11, 2018 at 5:29:47 PM UTC-5, Jonas Lund wrote:
>
> Interesting, but I don't think cross-type, name-based
>> designated initialization makes sense, thus only one
>> spreader of the same type should be allowed.
>>
>
> Depends on how one views the feature, name based could be useful for Q&D=
=20
> conversion between libraries with similar types but conversion operators=
=20
> might be a better fit for that use-case anyhow.
> But i agree the potential for errors could possibly another option where=
=20
> to restrict to same or parent classes as sources for initialization=20
> material (we could spread all parent types with different inputs) and=20
> partial overrides could also be useful (ie spread from the same type firs=
t=20
> then a parent type to replace parts of the object).
>
> There is another way to look at this. Let's consider
>> how do we designate initialize an aggregate with
>> base class:
>>
>> struct Base { int a, b; };
>> struct Derived : Base { double c; };
>>
>> Currently we can only do
>>
>> Derived{ .c =3D 3.0 }
>>
>> and Base is initialized with {}. We could treat
>> Base as a designater instead:
>>
>> Derived{ .Base {1, 2}, .c =3D 3.0 }
>>
>> Now if we treat Derived is its own base, we get
>>
>> Derived{ .Derived{ 1, 2, 2.0 }, .c =3D 3.0 }
>>
>> and .c =3D 3.0 should override 2.0, which is the
>> semantics you wanted.
>>
>
> I kinda see the logic in this syntax but i don't think it gives much=20
> benefits.
> One would usually provide source-args as values that the compiler can=20
> infer the type from so specifying it again would serve little purpose and=
=20
> the rest operator ... has a similar semantic meaning in other contexts li=
ke=20
> template pack spreading (and other languages also since this syntax would=
=20
> be very similar to what exists in ES6/TS where it is in widespread usage=
=20
> already)
>
The main reason we'd want to add designated-initializer syntax to C++ is=20
for C99 compatibility. (So the *current* design of=20
C++-designated-initializer syntax is a bit of a dumpster fire in that=20
respect: last I checked, it doesn't get us C compatibility at all.)
One of the flagship features of C99 designated-initializer syntax is that=
=20
you can designate fields in any order, and later designators will override=
=20
earlier ones. So you can say for example
struct Margins {
int left, right;
int top, bottom;
};
#define MARGINS(...) (struct Margins){ .left=3D1, .right=3D1, .top=3D1,=
=20
..bottom=3D1, ##__VA_ARGS__ }
void pageout(struct Margins args);
int main() {
pageout(MARGINS(.right=3D17, .top=3D8));
}
and `pageout` will get called with `Margins{.left=3D1, .right=3D17, .top=3D=
8,=20
..bottom=3D1}`.
It is generally true in C++ that a class is responsible for its own=20
initialization =E2=80=94 a derived class cannot "reach into" its parent cla=
ss and=20
directly initialize any of its parents' data members. Initialization of the=
=20
parent's data members must be done by the constructor of the parent class=
=20
itself.
When Zhihao said, "...Now if we treat Derived is its own base...", he's=20
talking about the C++11 feature called *delegating constructors*. This is=
=20
what lets us write
https://godbolt.org/z/INq03o
struct Base { int a, b; };
struct Derived : Base {
double c;
Derived(int a, int b, double c) : Base{a,b}, c{c} {}
Derived(double c) *: Derived{1, 2, 2.0}* { c =3D 3.0; }
};
The problem with this (for C++) is that once we've told the compiler to=20
construct Base::a, Base::b, and Derived::c "according to how Derived{1, 2,=
=20
2.0} would have done it"... well, those three members will have been=20
constructed, and so we cannot tell the compiler to go back and=20
"re-construct" Derived::c using some different value *instead*. We can't=
=20
mix delegating constructors with member-initializers.
Derived(double c) : Derived{1, 2, 2.0}, *c{c}* {} *// ERROR*
Now, for designated initializers, we could throw all this philosophical=20
correctness in the trash and just say that we can re-designate members as=
=20
many times as we like, and only the last one will stick. (We need that=20
feature for C99 compatibility anyway.) So we could say that the following=
=20
is magically well-formed after all:
Derived x =3D {.Derived{1, 2, 2.0}, .c{c}};
// or equivalently
Derived x =3D {.Derived(1, 2, 2.0), .c =3D c};
Then, to get the effect of Jonas's "spread operator," our user would simply=
=20
delegate to the copy constructor of `Derived`, like this:
Derived x =3D {.Derived(oldx), .c =3D c};
Or, in terms of Jonas's own example:
vec3 newvec{ .vec3{oldvec}, .y=3D20 };
(I must point out: engineering-wise, this is not a well-designed vec3=20
class. Aggregates are basically never what you want in real code. We=20
shouldn't encourage people to write aggregates. We'd rather write a proper=
=20
constructor, so that we could say e.g.
vec3 newvec =3D oldvec.with_y(20);
However, since the designated initializers proposal seems to have broken=20
the levees and is headed for town, I figure I should do my part to say how=
=20
designated initializers *should* be done, before it becomes another of=20
these features where six months past the ship date we discover that it's=20
been done wrong.)
=E2=80=93Arthur
--=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/591529e2-a9db-41a2-9534-1638bf7e6101%40isocpp.or=
g.
------=_Part_382_810184655.1541990217313
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Sunday, November 11, 2018 at 5:29:47 PM UTC-5, Jonas Lu=
nd 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"><blo=
ckquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-le=
ft:1px #ccc solid;padding-left:1ex"><div>Interesting, but I don't think=
cross-type, name-based<br></div><div>designated initialization makes sense=
, thus only one<br></div><div>spreader of the same type should be allowed.<=
br></div></blockquote><div><br></div><div>Depends on how one views the feat=
ure, name based could be useful for Q&D conversion between libraries wi=
th similar types but conversion operators might be a better fit for that us=
e-case anyhow.</div><div>But i agree the potential for errors could possibl=
y another option where to restrict to same or parent classes as sources for=
initialization material (we could spread all parent types with different i=
nputs) and partial overrides could also be useful (ie spread from the same =
type first then a parent type to replace parts of the object).</div><div><b=
r></div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8=
ex;border-left:1px #ccc solid;padding-left:1ex"><div>There is another way t=
o look at this.=C2=A0 Let's consider<br></div><div>how do we designate =
initialize an aggregate with<br></div><div>base class:<br></div><div><br></=
div><div>=C2=A0 struct Base { int a, b; };<br></div><div>=C2=A0 struct Deri=
ved : Base { double c; };<br></div><div><br></div><div>Currently we can onl=
y do<br></div><div><br></div><div>=C2=A0 Derived{ .c =3D 3.0 }<br></div><di=
v><br></div><div>and Base is initialized with {}.=C2=A0 We could treat<br><=
/div><div>Base as a designater instead:<br></div><div><br></div><div>=C2=A0=
Derived{ .Base {1, 2}, .c =3D 3.0 }<br></div><div><br></div><div>Now if we=
treat Derived is its own base, we get<br></div><div><br></div><div>=C2=A0 =
Derived{ .Derived{ 1, 2, 2.0 }, .c =3D 3.0 }<br></div><div><br></div><div>a=
nd .c =3D 3.0 should override 2.0, which is the<br></div><div>semantics you=
wanted.</div></blockquote><div><br></div><div>I kinda see the logic in thi=
s syntax but i don't think it gives much benefits.</div><div>One would =
usually provide source-args as values that the compiler can infer the type =
from so specifying it again would serve little purpose and the rest operato=
r ... has a similar semantic meaning in other contexts like template pack s=
preading (and other languages also since this syntax would be very similar =
to what exists in ES6/TS where it is in widespread usage already)</div></di=
v></blockquote><div><br></div><div>The main reason we'd want to add des=
ignated-initializer syntax to C++ is for C99 compatibility. =C2=A0(So the <=
i>current</i> design of C++-designated-initializer syntax is a bit of a dum=
pster fire in that respect: last I checked, it doesn't get us C compati=
bility at all.)</div><div><br></div><div>One of the flagship features of C9=
9 designated-initializer syntax is that you can designate fields in any ord=
er, and later designators will override earlier ones. So you can say for ex=
ample</div><div><br></div><div>=C2=A0 =C2=A0 struct Margins {</div><div>=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 int left, right;</div><div>=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 int top, bottom;<br></div><div>=C2=A0 =C2=A0 };<br></div><div>=C2=A0=
=C2=A0 #define MARGINS(...) (struct Margins){ .left=3D1, .right=3D1, .top=
=3D1, .bottom=3D1, ##__VA_ARGS__ }</div><div>=C2=A0 =C2=A0 void pageout(str=
uct Margins args);<br></div><div><br></div><div>=C2=A0 =C2=A0 int main() {<=
/div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 pageout(MARGINS(.right=3D17, .top=3D8=
));</div><div>=C2=A0 =C2=A0 }</div><div><br></div><div>and `pageout` will g=
et called with `Margins{.left=3D1, .right=3D17, .top=3D8, .bottom=3D1}`.</d=
iv><div><br></div><div>It is generally true in C++ that a class is responsi=
ble for its own initialization =E2=80=94 a derived class cannot "reach=
into" its parent class and directly initialize any of its parents'=
; data members. Initialization of the parent's data members must be don=
e by the constructor of the parent class itself.</div><div><br></div><div>W=
hen Zhihao said, "...Now if we treat Derived is its own base...",=
he's talking about the C++11 feature called <i>delegating constructors=
</i>. This is what lets us write</div><div><a href=3D"https://godbolt.org/z=
/INq03o">https://godbolt.org/z/INq03o</a><br></div><div><br></div><div>=C2=
=A0 =C2=A0 struct Base { int a, b; };<br></div><div><div>=C2=A0 =C2=A0 stru=
ct Derived : Base {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 double c;</div><d=
iv><br></div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 Derived(int a, int b, double =
c) : Base{a,b}, c{c} {}</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 Derived(doubl=
e c) <b>: Derived{1, 2, 2.0}</b> { c =3D 3.0; }</div><div>=C2=A0 =C2=A0 };<=
/div></div><div><br></div><div>The problem with this (for C++) is that once=
we've told the compiler to construct Base::a, Base::b, and Derived::c =
"according to how Derived{1, 2, 2.0} would have done it"... well,=
those three members will have been constructed, and so we cannot tell the =
compiler to go back and "re-construct" Derived::c using some diff=
erent value <i>instead</i>. =C2=A0We can't mix delegating constructors =
with member-initializers.</div><div><br></div><div>=C2=A0 =C2=A0 Derived(do=
uble c) : Derived{1, 2, 2.0}, <b>c{c}</b> {} =C2=A0<b>// ERROR</b></div><di=
v><br></div><div>Now, for designated initializers, we could throw all this =
philosophical correctness in the trash and just say that we can re-designat=
e members as many times as we like, and only the last one will stick. (We n=
eed that feature for C99 compatibility anyway.) So we could say that the fo=
llowing is magically well-formed after all:</div><div><br></div><div>=C2=A0=
=C2=A0 Derived x =3D {.Derived{1, 2, 2.0}, .c{c}};</div><div><div>=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 // or equivalently</div><div>=C2=A0 =C2=A0 Derived x =
=3D {.Derived(1, 2, 2.0), .c =3D c};</div></div><div><br></div><div>Then, t=
o get the effect of Jonas's "spread operator," our user would=
simply delegate to the copy constructor of `Derived`, like this:</div><div=
><br></div><div>=C2=A0 =C2=A0 Derived x =3D {.Derived(oldx), .c =3D c};</di=
v><div><br></div><div>Or, in terms of Jonas's own example:</div><div><b=
r></div><div>=C2=A0 =C2=A0=C2=A0<span style=3D"font-family: monospace; colo=
r: rgb(0, 0, 0);">vec3 newvec</span><span style=3D"font-family: monospace; =
color: rgb(102, 102, 0);">{</span><span style=3D"font-family: monospace; co=
lor: rgb(0, 0, 0);">=C2=A0</span><span style=3D"font-family: monospace; col=
or: rgb(102, 102, 0);">.</span><span style=3D"font-family: monospace; color=
: rgb(0, 0, 0);">v</span><span style=3D"font-family: monospace; color: rgb(=
0, 0, 0);">ec3</span><span style=3D"caret-color: rgb(102, 102, 0); color: r=
gb(102, 102, 0); font-family: monospace;">{</span><span style=3D"font-famil=
y: monospace; color: rgb(0, 0, 0);">oldvec</span><span style=3D"caret-color=
: rgb(102, 102, 0); color: rgb(102, 102, 0); font-family: monospace;">}</sp=
an><span style=3D"font-family: monospace; color: rgb(102, 102, 0);">,</span=
><span style=3D"font-family: monospace; color: rgb(0, 0, 0);">=C2=A0</span>=
<span style=3D"font-family: monospace; color: rgb(102, 102, 0);">.</span><s=
pan style=3D"font-family: monospace; color: rgb(0, 0, 0);">y</span><span st=
yle=3D"font-family: monospace; color: rgb(102, 102, 0);">=3D</span><span st=
yle=3D"font-family: monospace; color: rgb(0, 102, 102);">20</span><span sty=
le=3D"font-family: monospace; color: rgb(0, 0, 0);">=C2=A0</span><span styl=
e=3D"font-family: monospace; color: rgb(102, 102, 0);">};</span></div><div>=
<br></div><div>(I must point out: engineering-wise, this is not a well-desi=
gned vec3 class. Aggregates are basically never what you want in real code.=
We shouldn't encourage people to write aggregates. We'd rather wri=
te a proper constructor, so that we could say e.g.</div><div>=C2=A0 =C2=A0 =
vec3 newvec =3D oldvec.with_y(20);</div><div>However, since the designated =
initializers proposal seems to have broken the levees and is headed for tow=
n, I figure I should do my part to say how designated initializers <i>shoul=
d</i> be done, before it becomes another of these features where six months=
past the ship date we discover that it's been done wrong.)</div><div><=
br></div><div>=E2=80=93Arthur</div></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/591529e2-a9db-41a2-9534-1638bf7e6101%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/591529e2-a9db-41a2-9534-1638bf7e6101=
%40isocpp.org</a>.<br />
------=_Part_382_810184655.1541990217313--
------=_Part_381_2076920749.1541990217312--
.
Author: Zhihao Yuan <zy@miator.net>
Date: Mon, 12 Nov 2018 07:30:30 +0000
Raw View
This is a multi-part message in MIME format.
--b1_ffd2daedd8c3c95ab3c67848102e7814
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
We designed a limited form of compatibility to allow
a library author to ship a header with designated
initialization that can be included in both C and C++
code. Copying a piece of C code and making it
compile in C++ has never been our goal.
Aggregates have nothing wrong in type design.
In one project that I recently work on, all the
alternative types for signaling some states in
std::variant are aggregates, so the total number
of aggregate types in our code easily exceeded
the types with constructors :)
--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
_______________________________________________
=E2=80=90=E2=80=90=E2=80=90=E2=80=90=E2=80=90=E2=80=90=E2=80=90 Original Me=
ssage =E2=80=90=E2=80=90=E2=80=90=E2=80=90=E2=80=90=E2=80=90=E2=80=90
On Sunday, November 11, 2018 8:36 PM, Arthur O'Dwyer <arthur.j.odwyer@gmail=
..com> wrote:
> The main reason we'd want to add designated-initializer syntax to C++ is =
for C99 compatibility. (So the current design of C++-designated-initialize=
r syntax is a bit of a dumpster fire in that respect: last I checked, it do=
esn't get us C compatibility at all.)
>
> (I must point out: engineering-wise, this is not a well-designed vec3 cla=
ss. Aggregates are basically never what you want in real code. We shouldn't=
encourage people to write aggregates. [...])
--=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/8hYde2kmISHNM0Cfs9ekN8L16VEa2BqdU0onfDnK4t2rXh_K=
efM15W77lcbElZAotgMGj7FxLm76pm8d3XWZePbB7wUVA78Ot6L4MRK5dIg%3D%40miator.net=
..
--b1_ffd2daedd8c3c95ab3c67848102e7814
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div>We designed a limited form of compatibility to allow<br></div><div>a l=
ibrary author to ship a header with designated<br></div><div>initialization=
that can be included in both C and C++<br></div><div>code. Copying a=
piece of C code and making it<br></div><div>compile in C++ has never been =
our goal.<br></div><div><br></div><div>Aggregates have nothing wrong in typ=
e design.<br></div><div>In one project that I recently work on, all the<br>=
</div><div>alternative types for signaling some states in<br></div><div>std=
::variant are aggregates, so the total number<br></div><div>of aggregate ty=
pes in our code easily exceeded<br></div><div>the types with constructors :=
)<br></div><div><br></div><div class=3D"protonmail_signature_block"><div cl=
ass=3D"protonmail_signature_block-user"><div>--<br></div><div><span>Zhihao =
Yuan, ID lichray<br>The best way to predict the future is to invent it.<br>=
_______________________________________________</span></div></div><div clas=
s=3D"protonmail_signature_block-proton protonmail_signature_block-empty"><b=
r></div></div><div><br></div><div>=E2=80=90=E2=80=90=E2=80=90=E2=80=90=E2=
=80=90=E2=80=90=E2=80=90 Original Message =E2=80=90=E2=80=90=E2=80=90=E2=80=
=90=E2=80=90=E2=80=90=E2=80=90<br></div><div> On Sunday, November 11, 2018 =
8:36 PM, Arthur O'Dwyer <arthur.j.odwyer@gmail.com> wrote:<br></div><=
div> <br></div><blockquote type=3D"cite" class=3D"protonmail_quote"><div di=
r=3D"ltr"><div>The main reason we'd want to add designated-initializer synt=
ax to C++ is for C99 compatibility. (So the <i>current</i> design of =
C++-designated-initializer syntax is a bit of a dumpster fire in that respe=
ct: last I checked, it doesn't get us C compatibility at all.)<br></div><di=
v><br></div><div>(I must point out: engineering-wise, this is not a well-de=
signed vec3 class. Aggregates are basically never what you want in real cod=
e. We shouldn't encourage people to write aggregates. [...])<br></div></div=
></blockquote><div><br></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/8hYde2kmISHNM0Cfs9ekN8L16VEa2BqdU0onf=
DnK4t2rXh_KefM15W77lcbElZAotgMGj7FxLm76pm8d3XWZePbB7wUVA78Ot6L4MRK5dIg%3D%4=
0miator.net?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/8hYde2kmISHNM0Cfs9ekN8L16VEa2BqdU0onf=
DnK4t2rXh_KefM15W77lcbElZAotgMGj7FxLm76pm8d3XWZePbB7wUVA78Ot6L4MRK5dIg%3D%4=
0miator.net</a>.<br />
--b1_ffd2daedd8c3c95ab3c67848102e7814--
.
Author: Jonas Lund <whizzter@gmail.com>
Date: Tue, 13 Nov 2018 01:35:00 -0800 (PST)
Raw View
------=_Part_2311_992553938.1542101700316
Content-Type: multipart/alternative;
boundary="----=_Part_2312_1600984752.1542101700316"
------=_Part_2312_1600984752.1542101700316
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
>
>
> The main reason we'd want to add designated-initializer syntax to C++ is=
=20
> for C99 compatibility. (So the *current* design of=20
> C++-designated-initializer syntax is a bit of a dumpster fire in that=20
> respect: last I checked, it doesn't get us C compatibility at all.)
>
> One of the flagship features of C99 designated-initializer syntax is that=
=20
> you can designate fields in any order, and later designators will overrid=
e=20
> earlier ones. So you can say for example
>
> struct Margins {
> int left, right;
> int top, bottom;
> };
> #define MARGINS(...) (struct Margins){ .left=3D1, .right=3D1, .top=3D=
1,=20
> .bottom=3D1, ##__VA_ARGS__ }
> void pageout(struct Margins args);
>
> int main() {
> pageout(MARGINS(.right=3D17, .top=3D8));
> }
>
> and `pageout` will get called with `Margins{.left=3D1, .right=3D17, .top=
=3D8,=20
> .bottom=3D1}`.
>
C99 compat is one thing but i also think one should consider where we get=
=20
redundant code today without it. One typical scenario is specifying options=
=20
for creating a window object for example (like this margins example), often=
=20
this operation has quite a lot of options due to the nature of windows on=
=20
various platforms but this usually leads to one of 3 bad scenarios:
1: untyped passing of options
2: many constructors
3: an options object passed that is built with a builder pattern
The first option is usually the least code but has it's downsides whilst=20
the last 2 options leads to quite a bit of code doing more or less the same=
=20
things.
Passing an options object with designated initializers would allow for only=
=20
those option values that are actually used in each instance to be passed=20
with the rest being initialized by the member initializer specification by=
=20
the option type and in this sense C++ does it better already since we don't=
=20
need any extra MARGINS macro.
=20
>
> It is generally true in C++ that a class is responsible for its own=20
> initialization =E2=80=94 a derived class cannot "reach into" its parent c=
lass and=20
> directly initialize any of its parents' data members. Initialization of t=
he=20
> parent's data members must be done by the constructor of the parent class=
=20
> itself.
>
> When Zhihao said, "...Now if we treat Derived is its own base...", he's=
=20
> talking about the C++11 feature called *delegating constructors*. This is=
=20
> what lets us write
> https://godbolt.org/z/INq03o
>
> struct Base { int a, b; };
> struct Derived : Base {
> double c;
>
> Derived(int a, int b, double c) : Base{a,b}, c{c} {}
> Derived(double c) *: Derived{1, 2, 2.0}* { c =3D 3.0; }
> };
>
> The problem with this (for C++) is that once we've told the compiler to=
=20
> construct Base::a, Base::b, and Derived::c "according to how Derived{1, 2=
,=20
> 2.0} would have done it"... well, those three members will have been=20
> constructed, and so we cannot tell the compiler to go back and=20
> "re-construct" Derived::c using some different value *instead*. We can't=
=20
> mix delegating constructors with member-initializers.
>
> Derived(double c) : Derived{1, 2, 2.0}, *c{c}* {} *// ERROR*
>
> Now, for designated initializers, we could throw all this philosophical=
=20
> correctness in the trash and just say that we can re-designate members as=
=20
> many times as we like, and only the last one will stick. (We need that=20
> feature for C99 compatibility anyway.) So we could say that the following=
=20
> is magically well-formed after all:
>
> Derived x =3D {.Derived{1, 2, 2.0}, .c{c}};
> // or equivalently
> Derived x =3D {.Derived(1, 2, 2.0), .c =3D c};
>
> Then, to get the effect of Jonas's "spread operator," our user would=20
> simply delegate to the copy constructor of `Derived`, like this:
>
> Derived x =3D {.Derived(oldx), .c =3D c};
>
> Or, in terms of Jonas's own example:
>
> vec3 newvec{ .vec3{oldvec}, .y=3D20 };
>
> (I must point out: engineering-wise, this is not a well-designed vec3=20
> class. Aggregates are basically never what you want in real code. We=20
> shouldn't encourage people to write aggregates. We'd rather write a prope=
r=20
> constructor, so that we could say e.g.
> vec3 newvec =3D oldvec.with_y(20);
> However, since the designated initializers proposal seems to have broken=
=20
> the levees and is headed for town, I figure I should do my part to say ho=
w=20
> designated initializers *should* be done, before it becomes another of=20
> these features where six months past the ship date we discover that it's=
=20
> been done wrong.)
>
>
I'll admit i skimped on providing member defaults on that example so the=20
struct should've looked like this to begin with:
struct vec3 { float x=3D0,y=3D0,z=3D0; };
But why exactly is aggregates bad? Before members could have initializers=
=20
there was a risk values weren't defined (that's fixed now) and another=20
argument is that an outside initialization of data would miss including=20
values when the class was redefined so it was better to have it all=20
included in the class itself (the with_y clone function to ensure getting a=
=20
sane copy) and this is what a spread operator would fix.
So this proposal is basically to make plain-old-data into not really=20
needing anything more than just an aggregate without the past weakness that=
=20
was associated with it.
The vec3 given a spread operator being present could even be all-const:
struct vec3 { const float x=3D0,y=3D0,z=3D0; };
Without even impacting usability and would certainly be very defined and=20
safe.
--=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/4071ce61-ef01-4b90-934d-463a693abf09%40isocpp.or=
g.
------=_Part_2312_1600984752.1542101700316
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<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><br></di=
v><div>The main reason we'd want to add designated-initializer syntax t=
o C++ is for C99 compatibility. =C2=A0(So the <i>current</i> design of C++-=
designated-initializer syntax is a bit of a dumpster fire in that respect: =
last I checked, it doesn't get us C compatibility at all.)</div><div><b=
r></div><div>One of the flagship features of C99 designated-initializer syn=
tax is that you can designate fields in any order, and later designators wi=
ll override earlier ones. So you can say for example</div><div><br></div><d=
iv>=C2=A0 =C2=A0 struct Margins {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 int=
left, right;</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 int top, bottom;<br></d=
iv><div>=C2=A0 =C2=A0 };<br></div><div>=C2=A0 =C2=A0 #define MARGINS(...) (=
struct Margins){ .left=3D1, .right=3D1, .top=3D1, .bottom=3D1, ##__VA_ARGS_=
_ }</div><div>=C2=A0 =C2=A0 void pageout(struct Margins args);<br></div><di=
v><br></div><div>=C2=A0 =C2=A0 int main() {</div><div>=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 pageout(MARGINS(.right=3D17, .top=3D8));</div><div>=C2=A0 =C2=A0 }</=
div><div><br></div><div>and `pageout` will get called with `Margins{.left=
=3D1, .right=3D17, .top=3D8, .bottom=3D1}`.</div></div></blockquote><div><b=
r></div><div><div>C99 compat is one thing but i also think one should consi=
der where we get redundant code today without it. One typical scenario is s=
pecifying options for creating a window object for example (like this margi=
ns example), often this operation has quite a lot of options due to the nat=
ure of windows on various platforms but this usually leads to one of 3 bad =
scenarios:</div><div>1: untyped passing of options</div><div>2: many constr=
uctors</div><div>3: an options object passed that is built with a builder p=
attern</div><div><br></div><div>The first option is usually the least code =
but has it's downsides whilst the last 2 options leads to quite a bit o=
f code doing more or less the same things.</div><div><br></div><div>Passing=
an options object with designated initializers would allow for only those =
option values that are actually used in each instance to be passed with the=
rest being initialized by the member initializer specification by the opti=
on type and in this sense C++ does it better already since we don't nee=
d any extra MARGINS macro.</div></div><div>=C2=A0</div><blockquote class=3D=
"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc s=
olid;padding-left: 1ex;"><div dir=3D"ltr"><div><br></div><div>It is general=
ly true in C++ that a class is responsible for its own initialization =E2=
=80=94 a derived class cannot "reach into" its parent class and d=
irectly initialize any of its parents' data members. Initialization of =
the parent's data members must be done by the constructor of the parent=
class itself.</div><div><br></div><div>When Zhihao said, "...Now if w=
e treat Derived is its own base...", he's talking about the C++11 =
feature called <i>delegating constructors</i>. This is what lets us write</=
div><div><a href=3D"https://godbolt.org/z/INq03o" target=3D"_blank" rel=3D"=
nofollow" onmousedown=3D"this.href=3D'https://www.google.com/url?q\x3dh=
ttps%3A%2F%2Fgodbolt.org%2Fz%2FINq03o\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQ=
jCNHId-Kcs389y1qKDV3VlQtzD1ChRA';return true;" onclick=3D"this.href=3D&=
#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgodbolt.org%2Fz%2FINq03o\=
x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHId-Kcs389y1qKDV3VlQtzD1ChRA';r=
eturn true;">https://godbolt.org/z/INq03o</a><br></div><div><br></div><div>=
=C2=A0 =C2=A0 struct Base { int a, b; };<br></div><div><div>=C2=A0 =C2=A0 s=
truct Derived : Base {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 double c;</div=
><div><br></div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 Derived(int a, int b, doub=
le c) : Base{a,b}, c{c} {}</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 Derived(do=
uble c) <b>: Derived{1, 2, 2.0}</b> { c =3D 3.0; }</div><div>=C2=A0 =C2=A0 =
};</div></div><div><br></div><div>The problem with this (for C++) is that o=
nce we've told the compiler to construct Base::a, Base::b, and Derived:=
:c "according to how Derived{1, 2, 2.0} would have done it"... we=
ll, those three members will have been constructed, and so we cannot tell t=
he compiler to go back and "re-construct" Derived::c using some d=
ifferent value <i>instead</i>. =C2=A0We can't mix delegating constructo=
rs with member-initializers.</div><div><br></div><div>=C2=A0 =C2=A0 Derived=
(double c) : Derived{1, 2, 2.0}, <b>c{c}</b> {} =C2=A0<b>// ERROR</b></div>=
<div><br></div><div>Now, for designated initializers, we could throw all th=
is philosophical correctness in the trash and just say that we can re-desig=
nate members as many times as we like, and only the last one will stick. (W=
e need that feature for C99 compatibility anyway.) So we could say that the=
following is magically well-formed after all:</div><div><br></div><div>=C2=
=A0 =C2=A0 Derived x =3D {.Derived{1, 2, 2.0}, .c{c}};</div><div><div>=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 // or equivalently</div><div>=C2=A0 =C2=A0 Derived=
x =3D {.Derived(1, 2, 2.0), .c =3D c};</div></div><div><br></div><div>Then=
, to get the effect of Jonas's "spread operator," our user wo=
uld simply delegate to the copy constructor of `Derived`, like this:</div><=
div><br></div><div>=C2=A0 =C2=A0 Derived x =3D {.Derived(oldx), .c =3D c};<=
/div><div><br></div><div>Or, in terms of Jonas's own example:</div><div=
><br></div><div>=C2=A0 =C2=A0=C2=A0<span style=3D"font-family:monospace;col=
or:rgb(0,0,0)">vec3 newvec</span><span style=3D"font-family:monospace;color=
:rgb(102,102,0)">{</span><span style=3D"font-family:monospace;color:rgb(0,0=
,0)">=C2=A0</span><span style=3D"font-family:monospace;color:rgb(102,102,0)=
">.</span><span style=3D"font-family:monospace;color:rgb(0,0,0)">v</span><s=
pan style=3D"font-family:monospace;color:rgb(0,0,0)">ec3</span><span style=
=3D"color:rgb(102,102,0);font-family:monospace">{</span><span style=3D"font=
-family:monospace;color:rgb(0,0,0)">oldvec</span><span style=3D"color:rgb(1=
02,102,0);font-family:monospace">}</span><span style=3D"font-family:monospa=
ce;color:rgb(102,102,0)">,</span><span style=3D"font-family:monospace;color=
:rgb(0,0,0)">=C2=A0</span><span style=3D"font-family:monospace;color:rgb(10=
2,102,0)">.</span><span style=3D"font-family:monospace;color:rgb(0,0,0)">y<=
/span><span style=3D"font-family:monospace;color:rgb(102,102,0)">=3D</span>=
<span style=3D"font-family:monospace;color:rgb(0,102,102)">20</span><span s=
tyle=3D"font-family:monospace;color:rgb(0,0,0)">=C2=A0</span><span style=3D=
"font-family:monospace;color:rgb(102,102,0)">}<wbr>;</span></div><div><br><=
/div><div>(I must point out: engineering-wise, this is not a well-designed =
vec3 class. Aggregates are basically never what you want in real code. We s=
houldn't encourage people to write aggregates. We'd rather write a =
proper constructor, so that we could say e.g.</div><div>=C2=A0 =C2=A0 vec3 =
newvec =3D oldvec.with_y(20);</div><div>However, since the designated initi=
alizers proposal seems to have broken the levees and is headed for town, I =
figure I should do my part to say how designated initializers <i>should</i>=
be done, before it becomes another of these features where six months past=
the ship date we discover that it's been done wrong.)</div><div><br></=
div></div></blockquote><div><br></div><div>I'll admit i skimped on prov=
iding member defaults on that example so the struct should've looked li=
ke this to begin with:</div><div><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; overflow-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;" cla=
ss=3D"styled-by-prettify"> vec3 </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-pret=
tify">float</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> x</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</sp=
an><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">y</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #066;" cl=
ass=3D"styled-by-prettify">0</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify">z</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
=3D</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 st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">};</span></div></code></div><div><=
br></div></div><div>But why exactly is aggregates bad? Before members could=
have initializers there was a risk values weren't defined (that's =
fixed now) and another argument is that an outside initialization of data w=
ould miss including values when the class was redefined so it was better to=
have it all included in the class itself (the with_y clone function to ens=
ure getting a sane copy) and this is what a spread operator would fix.</div=
><div><br></div><div>So this proposal is basically to make plain-old-data i=
nto not really needing anything more than just an aggregate without the pas=
t weakness that was associated with it.</div><div><br></div><div>The vec3 g=
iven a spread operator being present could even be all-const:</div><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; overflow-w=
rap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"=
><span style=3D"color: #008;" class=3D"styled-by-prettify">struct</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> vec3 </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">const</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: #000;" class=3D"styled=
-by-prettify"> x</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">=3D</span><span style=3D"color: #066;" class=3D"styled-by-prettify">0=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify">y</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"col=
or: #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">z</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">=3D</span><span style=3D"color: #066;" class=3D"styled-by-pr=
ettify">0</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">};</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"><br></span></div></code></d=
iv><div><br>Without even impacting usability and would certainly be very de=
fined and safe.</div><div><br></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/4071ce61-ef01-4b90-934d-463a693abf09%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/4071ce61-ef01-4b90-934d-463a693abf09=
%40isocpp.org</a>.<br />
------=_Part_2312_1600984752.1542101700316--
------=_Part_2311_992553938.1542101700316--
.
Author: Jonas Lund <whizzter@gmail.com>
Date: Tue, 13 Nov 2018 01:45:20 -0800 (PST)
Raw View
------=_Part_456_30490288.1542102320443
Content-Type: multipart/alternative;
boundary="----=_Part_457_1566134876.1542102320444"
------=_Part_457_1566134876.1542102320444
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
>
>
> However, since the designated initializers proposal seems to have broken=
=20
> the levees and is headed for town, I figure I should do my part to say ho=
w=20
> designated initializers *should* be done, before it becomes another of=20
> these features where six months past the ship date we discover that it's=
=20
> been done wrong.)
>
> =E2=80=93Arthur
>
I'd like to add, a sanely defined variant of this is to be preferred and=20
having a limited variant (since the main benefit is to make aggregates=20
useful/safe) is totally fine in my opinion.
Could even be that this was kind of initialization was forbidden for=20
anything that isn't default copy/move constructed (since that'd imply the=
=20
same kind of member-to-member copying)
--=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/6c27bd08-1806-4d76-bf7c-d5aea7e36728%40isocpp.or=
g.
------=_Part_457_1566134876.1542102320444
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"l=
tr"><br><div>However, since the designated initializers proposal seems to h=
ave broken the levees and is headed for town, I figure I should do my part =
to say how designated initializers <i>should</i> be done, before it becomes=
another of these features where six months past the ship date we discover =
that it's been done wrong.)</div><div><br></div><div>=E2=80=93Arthur</d=
iv></div></blockquote><div><br></div><div>I'd like to add, a sanely def=
ined variant of this is to be preferred and having a limited variant (since=
the main benefit is to make aggregates useful/safe) is totally fine in my =
opinion.</div><div><br></div><div>Could even be that this was kind of initi=
alization was forbidden for anything that isn't default copy/move const=
ructed (since that'd imply the same kind of member-to-member copying)</=
div><div><br></div></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/6c27bd08-1806-4d76-bf7c-d5aea7e36728%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/6c27bd08-1806-4d76-bf7c-d5aea7e36728=
%40isocpp.org</a>.<br />
------=_Part_457_1566134876.1542102320444--
------=_Part_456_30490288.1542102320443--
.