Topic: Comments on N4424: inline variables


Author: David Krauss <potswa@mac.com>
Date: Fri, 08 May 2015 14:38:55 +0800
Raw View
--Apple-Mail=_F023BB05-1D4D-4322-A68F-F8D301B03452
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=UTF-8

Sorry for the late message. This should be relevant to CWG.

Regarding N4424, the main problem is not that there isn=E2=80=99t currently=
 a viable workaround, but that it doesn=E2=80=99t work very well due to oth=
er deficiencies in the standard.

Declarations with non-constant initializers in multiple TUs have unordered =
dynamic initialization ([basic.start.init] =C2=A73.6.2/2). Such initializat=
ion is unsequenced with respect to anything else that happens before entry =
into main(). It=E2=80=99s UB to access such a variable from within another =
initializer or any function called during startup.

So, if two declarations use this new feature and one depends on the other, =
it=E2=80=99s UB. If one global uses the feature and another doesn=E2=80=99t=
, and there=E2=80=99s a dependency, it=E2=80=99s UB.

I recall discussing the solution with Richard on this (std-proposals) list,=
 but its implementation may be nontrivial. The problem is that implementati=
ons are allowed to use multiple threads to initialize TUs in parallel (the =
order of initializations in one TU being well-defined). Assigning a sensibl=
e order to unordered initializations then requires adding synchronization i=
nto dynamic initialization subroutines. This synchronization would be just =
the same as what=E2=80=99s already used for static local variables, but it=
=E2=80=99s still something that needs to be implemented. (Implementation ma=
y be simpler for single-threaded initialization, but the standardese needs =
to cover all implementations.)

Checking the Wiki, concern over synchronization was raised in EWG by Bjarne=
 and others.

=E2=80=94=E2=80=94=E2=80=94
If the proposal doesn=E2=80=99t make it into C++17, or even if it does, her=
e=E2=80=99s a simpler alternative just for constexpr.

The motivating problem is most urgent (UB in the standard library!) and eas=
iest to solve for objects with static initialization. Why not fix externall=
y-linked constexpr variables, without adding any new syntax? Let extern con=
stexpr indicate vague linkage.

This isn=E2=80=99t a breaking change, since any program that declares a var=
iable as extern constexpr in two TUs is currently ill-formed. Non-constexpr=
 but extern declarations may still occur in other TUs, although they are se=
ldom used.

Some programmers care about multiple-definition diagnostics; this functiona=
lity could be restored with a little extra implementation. Current linkers =
avoid comparing function bodies byte-by-byte, but such is reasonable for ob=
ject representations of constexpr objects. Anyway, this issue is intrinsic =
to solving the problem, and the alternative is near-certain ODR violation.

It fits with the current meaning of extern which is simply that the variabl=
e is shared between TUs. Users can easily apply the solution without thinki=
ng about a new inline feature, but only considering that the implicit stati=
c is problematic.

Actually I started writing such a proposal before deciding to go with my ow=
n inline variables paper instead. I should have pursued both in parallel. A=
lthough various interpretations of the inline keyword can extrapolate corre=
ct semantics for shared constexpr variables, there=E2=80=99s no reason to d=
epend on anything contentious, or to preserve the brokenness of extern cons=
texpr. Let inline constexpr and extern constexpr mean the same thing, and d=
on=E2=80=99t make users wait for their implementation to get around to inli=
ne.

(For that matter, don=E2=80=99t forget that inline needs to override the im=
plicit static bestowed by constexpr! I don=E2=80=99t see this in the propos=
ed standardese.)

=E2=80=94=E2=80=94=E2=80=94
Just as an aside for folks following along, here is a fleshed-out workaroun=
d. All of this goes into a header, and it causes make_side_effects to be ca=
lled at startup if it=E2=80=99s included anywhere =E2=80=94 but when it=E2=
=80=99s called might be anytime from first-thing to just-before-main. The t=
ype foo is insignificant, it might be int or anything.

template< typename =3D void >
struct wrap_global {
    static foo thing;
};

template< typename t >
foo wrap_global< t >::thing =3D make_side_effects();

static_assert( & wrap_global<>::thing, "" ); // Require object to exist, al=
ong with its definition.

--=20

---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.

--Apple-Mail=_F023BB05-1D4D-4322-A68F-F8D301B03452
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=UTF-8

<html><head><meta http-equiv=3D"Content-Type" content=3D"text/html charset=
=3Dutf-8"></head><body style=3D"word-wrap: break-word; -webkit-nbsp-mode: s=
pace; -webkit-line-break: after-white-space;" class=3D""><div class=3D"">So=
rry for the late message. This should be relevant to CWG.</div><div class=
=3D""><br class=3D""></div><div class=3D"">Regarding N4424, the main proble=
m is not that there isn=E2=80=99t currently a viable workaround, but that i=
t doesn=E2=80=99t work very well due to other deficiencies in the standard.=
</div><div class=3D""><br class=3D""></div><div class=3D"">Declarations wit=
h non-constant initializers in multiple TUs have unordered dynamic initiali=
zation ([basic.start.init] =C2=A73.6.2/2). Such initialization is unsequenc=
ed with respect to anything else that happens before entry into <font face=
=3D"Courier" class=3D"">main()</font>. It=E2=80=99s UB to access such a var=
iable from within another initializer or any function called during startup=
..</div><div class=3D""><br class=3D""></div><div class=3D"">So, if two decl=
arations use this new feature and one depends on the other, it=E2=80=99s UB=
.. If one global uses the feature and another doesn=E2=80=99t, and there=E2=
=80=99s a dependency, it=E2=80=99s UB.</div><div class=3D""><br class=3D"">=
</div><div class=3D"">I recall discussing the solution with Richard on this=
 (std-proposals) list, but its implementation may be nontrivial. The proble=
m is that implementations are allowed to use multiple threads to initialize=
 TUs in parallel (the order of initializations in one TU being well-defined=
). Assigning a sensible order to unordered initializations then requires ad=
ding synchronization into dynamic initialization subroutines. This synchron=
ization would be just the same as what=E2=80=99s already used for static lo=
cal variables, but it=E2=80=99s still something that needs to be implemente=
d. (Implementation may be simpler for single-threaded initialization, but t=
he standardese needs to cover all implementations.)</div><div class=3D""><b=
r class=3D""></div><div class=3D""><div class=3D"">Checking the Wiki, conce=
rn over synchronization was raised in EWG by Bjarne and others.</div></div>=
<div class=3D""><br class=3D""></div><div class=3D"">=E2=80=94=E2=80=94=E2=
=80=94</div><div class=3D"">If the proposal doesn=E2=80=99t make it into C+=
+17, or even if it does, here=E2=80=99s a simpler alternative just for&nbsp=
;<font face=3D"Courier" class=3D"">constexpr</font>.</div><div class=3D""><=
div class=3D""><br class=3D""></div><div class=3D"">The motivating problem =
is most urgent (UB in the standard library!) and easiest to solve for objec=
ts with static initialization. Why not fix externally-linked constexpr vari=
ables, without adding any new syntax? Let&nbsp;<font face=3D"Courier" class=
=3D"">extern constexpr</font>&nbsp;indicate vague linkage.</div><div class=
=3D""><br class=3D""></div><div class=3D"">This isn=E2=80=99t a breaking ch=
ange, since any program that declares a variable as&nbsp;<font face=3D"Cour=
ier" class=3D"">extern constexpr</font>&nbsp;in two TUs is currently ill-fo=
rmed. Non-<font face=3D"Courier" class=3D"">constexpr</font>&nbsp;but&nbsp;=
<font face=3D"Courier" class=3D"">extern</font>&nbsp;declarations may still=
 occur in other TUs, although they are seldom used.</div><div class=3D""><b=
r class=3D""></div><div class=3D"">Some programmers care about multiple-def=
inition diagnostics; this functionality could be restored with a little ext=
ra implementation. Current linkers avoid comparing function bodies byte-by-=
byte, but such is reasonable for object representations of constexpr object=
s. Anyway, this issue is intrinsic to solving the problem, and the alternat=
ive is near-certain ODR violation.</div><div class=3D""><br class=3D""></di=
v><div class=3D"">It fits with the current meaning of&nbsp;<span style=3D"f=
ont-family: Courier;" class=3D"">extern</span>&nbsp;which is simply that th=
e variable is shared between TUs. Users can easily apply the solution witho=
ut thinking about a new&nbsp;<font face=3D"Courier" class=3D"">inline</font=
>&nbsp;feature, but only considering that the implicit&nbsp;<font face=3D"C=
ourier" class=3D"">static</font>&nbsp;is problematic.</div><div class=3D"">=
<br class=3D""></div><div class=3D"">Actually I started writing such a prop=
osal before deciding to go with my own&nbsp;inline&nbsp;variables paper ins=
tead. I should have pursued both in parallel. Although various interpretati=
ons of the&nbsp;<font face=3D"Courier" class=3D"">inline</font>&nbsp;keywor=
d can extrapolate correct semantics for shared&nbsp;<font face=3D"Courier" =
class=3D"">constexpr</font>&nbsp;variables, there=E2=80=99s no reason to de=
pend on anything contentious, or to preserve the brokenness of&nbsp;<font f=
ace=3D"Courier" class=3D"">extern constexpr</font>. Let <font face=3D"Couri=
er" class=3D"">inline constexpr</font> and <font face=3D"Courier" class=3D"=
">extern constexpr</font> mean the same thing, and don=E2=80=99t make users=
 wait for their implementation to get around to&nbsp;<font face=3D"Courier"=
 class=3D"">inline</font>.</div></div><div class=3D""><br class=3D""></div>=
<div class=3D"">(For that matter, don=E2=80=99t forget that <font face=3D"C=
ourier" class=3D"">inline</font> needs to override the implicit <font face=
=3D"Courier" class=3D"">static</font> bestowed by <font face=3D"Courier" cl=
ass=3D"">constexpr</font>! I don=E2=80=99t see this in the proposed standar=
dese.)</div><div class=3D""><br class=3D""></div><div class=3D"">=E2=80=94=
=E2=80=94=E2=80=94</div><div class=3D"">Just as an aside for folks followin=
g along, here is a fleshed-out workaround. All of this goes into a header, =
and it causes <font face=3D"Courier" class=3D"">make_side_effects</font> to=
 be called at startup if it=E2=80=99s included anywhere =E2=80=94 but <i cl=
ass=3D"">when</i>&nbsp;it=E2=80=99s called might be anytime from first-thin=
g to just-before-<font face=3D"Courier" class=3D"">main</font>. The type <f=
ont face=3D"Courier" class=3D"">foo</font> is insignificant, it might be <f=
ont face=3D"Courier" class=3D"">int</font> or anything.</div><div class=3D"=
"><br class=3D""></div><div class=3D""><font face=3D"Courier" class=3D"">te=
mplate&lt; typename =3D void &gt;</font></div><div class=3D""><font face=3D=
"Courier" class=3D"">struct wrap_global {</font></div><div class=3D""><font=
 face=3D"Courier" class=3D"">&nbsp; &nbsp; static foo thing;</font></div><d=
iv class=3D""><font face=3D"Courier" class=3D"">};</font></div><div class=
=3D""><font face=3D"Courier" class=3D""><br class=3D""></font></div><div cl=
ass=3D""><font face=3D"Courier" class=3D"">template&lt; typename t &gt;</fo=
nt></div><div class=3D""><font face=3D"Courier" class=3D"">foo wrap_global&=
lt; t &gt;::thing =3D make_side_effects();</font></div><div class=3D""><fon=
t face=3D"Courier" class=3D""><br class=3D""></font></div><div class=3D""><=
font face=3D"Courier" class=3D"">static_assert( &amp; wrap_global&lt;&gt;::=
thing, "" ); // Require object to exist, along with its definition.</font><=
/div></body></html>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

--Apple-Mail=_F023BB05-1D4D-4322-A68F-F8D301B03452--

.