Topic: Stateless Subobjects and Types


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Thu, 7 Jul 2016 19:16:42 -0700 (PDT)
Raw View
------=_Part_4960_1290977361.1467944202609
Content-Type: multipart/alternative;
 boundary="----=_Part_4961_691447147.1467944202609"

------=_Part_4961_691447147.1467944202609
Content-Type: text/plain; charset=UTF-8

A while back, I came up with a proposal for stateless types, as well as
inner classes and mixin support. At the time, I thought that all three
ideas built on one another, such that only providing one of them would not
be a particularly worthwhile feature. Since then, I've had a re-evaluation
of that notion.

So here is what I currently think in terms of just stateless stuff. The
proposal is available in HTML and Markdown formats.

A quick overview:

* You can declare that a empty type which is used as a subobject of a class
is stateless (taking up no space in the layout). Stateless subobjects
behave like regular objects where possible. This works for both members
*and* base classes; people keep forgetting that EBO is *optional* if the
class isn't standard layout.
* You can declare that a type will be used in a stateless fashion whenever
it is declared as a subobject of another type. It can be used normally in
non-stateless ways, but it must conform to the requirements of stateless
subobject (ie: the class must be empty).
* You can condition either kind of declaration on a constant expression,
like `noexcept` conditions.

--
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/0f692abf-2b9b-4f62-b93d-643c43a0dc26%40isocpp.org.

------=_Part_4961_691447147.1467944202609
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">A while back, I came up with a proposal for stateless type=
s, as well as inner classes and mixin support. At the time, I thought that =
all three ideas built on one another, such that only providing one of them =
would not be a particularly worthwhile feature. Since then, I&#39;ve had a =
re-evaluation of that notion.<br><br>So here is what I currently think in t=
erms of just stateless stuff. The proposal is available in HTML and Markdow=
n formats.<br><br>A quick overview:<br><br>* You can declare that a empty t=
ype which is used as a subobject of a class is stateless (taking up no spac=
e in the layout). Stateless subobjects behave like regular objects where po=
ssible. This works for both members <i>and</i> base classes; people keep fo=
rgetting that EBO is <i>optional</i> if the class isn&#39;t standard layout=
..<br>* You can declare that a type will be used in a stateless fashion when=
ever it is declared as a subobject of another type. It can be used normally=
 in non-stateless ways, but it must conform to the requirements of stateles=
s subobject (ie: the class must be empty).<br>* You can condition either ki=
nd of declaration on a constant expression, like `noexcept` conditions.<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/0f692abf-2b9b-4f62-b93d-643c43a0dc26%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/0f692abf-2b9b-4f62-b93d-643c43a0dc26=
%40isocpp.org</a>.<br />

------=_Part_4961_691447147.1467944202609--

------=_Part_4960_1290977361.1467944202609
Content-Type: text/html; charset=UTF-8; name="Stateless Subobjects.html"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename="Stateless Subobjects.html"
X-Attachment-Id: 5f437a13-6a38-46bb-b27b-42875756a60e
Content-ID: <5f437a13-6a38-46bb-b27b-42875756a60e>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.=
w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns=3D"http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8" =
/>
  <meta http-equiv=3D"Content-Style-Type" content=3D"text/css" />
  <meta name=3D"generator" content=3D"pandoc" />
  <title>Stateless Subobjects and Types, v0.7</title>
  <style type=3D"text/css">code{white-space: pre;}</style>
</head>
<body>
<div id=3D"header">
<h1 class=3D"title">Stateless Subobjects and Types, v0.7</h1>
<h3 class=3D"date">July 7, 2016</h3>
</div>
<p>This proposal specifies the ability to declare member and base class sub=
objects which do not take up space in the objects they are contained within=
.. It also allows the user to define classes which will always be used in su=
ch a fashion.</p>
<h1 id=3D"motivation-and-scope">Motivation and Scope</h1>
<p>An object is stateless, conceptually speaking, if it has no non-static d=
ata members. As such, the state of any particular instance is no different =
from another. Because of this, there is no conceptual reason why a stateles=
s object needs to have a region of storage associated with it.</p>
<p>In C++, a class would be stateless if it has no non-static data members =
(NSDMs) and all of its base classes likewise are stateless as well. <code>i=
s_empty_v</code> qualifies as a useful test, but technically other classes =
could qualify as well (those with virtual members/base classes).</p>
<p>There are many times when a user wants to use a class that the user prov=
ides, but the class may or may not be logically stateless. If it is statele=
ss, then it would be best if the class which uses it would not grow in size=
 simply due to the presence of the stateless subobject. After all, a concep=
tually stateless object does not need to take up space to do its job.</p>
<p>To avoid this, users will frequently use standard layout rules and the e=
mpty base optimization to allow them to have access to a stateless subobjec=
t:</p>
<pre><code>template&lt;typename Alloc&gt;
struct DataBlock : public Alloc
{
};</code></pre>
<p>In this case, if <code>Alloc</code> is empty, then so long as <code>Data=
Block</code> follows standard layout rules, the user is guaranteed that <co=
de>DataBlock</code> is no larger than it would have been if <code>Alloc</co=
de> were not empty. Even if it does not follow standard layout, the compile=
r is free to optimize the empty base <code>Alloc</code> away.</p>
<p>There are of course problems with such a use. If <code>Alloc</code> is n=
ot empty (and <code>DataBlock</code> does not require that it is), and <cod=
e>Alloc</code> declares a virtual function, it is possible that <code>DataB=
lock&lt;Alloc&gt;</code> will accidentally override that virtual function. =
Or not quite override it and cause a compile error. Whereas if <code>Alloc<=
/code> were a non-static data member, this could easily be avoided.</p>
<p>Equally importantly, this use of <code>Alloc</code> is simply not how a =
user would naturally write this class. Inheritance is supposed to model an =
&quot;is a&quot; relationship. Yet conceptually, <code>DataBlock</code> is =
not an <code>Alloc</code>; it <em>has</em> an <code>Alloc</code>. <code>Dat=
aBlock</code> uses inheritance, not to model a relationship, but as an opti=
mization tool, to keep the class from growing unnecessarily.</p>
<p>The intent of this proposal is to permit, among other things, classes li=
ke <code>DataBlock</code> to declare <code>Alloc</code> as a non-static dat=
a member. And if <code>Alloc</code> is empty, then <code>DataBlock</code> c=
an use syntax to make the <code>Alloc</code> NSDM take up no space in <code=
>DataBlock</code>'s layout.</p>
<p>This would also be recursive, so that if <code>Alloc</code> had no NSDMs=
, and <code>DataBlock&lt;Alloc&gt;</code> had no NSDMs besides the <code>Al=
loc</code> member, then <code>DataBlock&lt;Alloc&gt;</code> would also be c=
onsidered an empty type. And therefore, some other type could use it in a s=
tateless fashion.</p>
<h1 id=3D"design">Design</h1>
<p>We define two concepts: stateless subobjects and stateless classes. A st=
ateless class is really just shorthand for the former; it declares that ins=
tances of the class can only be created as stateless subobjects of some oth=
er type.</p>
<p>Note: The following syntax is entirely preliminary. This proposal is not=
 wedded to the idea of introducing a new keyword or somesuch. This syntax i=
s here simply for the sake of understanding how the functionality should ge=
nerally be specified. The eventual syntax could be a contextual keyword lik=
e <code>final</code> and <code>override</code>, or it could be something el=
se.</p>
<h3 id=3D"stateless-subobojects">Stateless subobojects</h3>
<p>A non-static data member subobject of a type can be declared stateless w=
ith the following syntax:</p>
<pre><code>struct Data
{
    stateless Type val;
};</code></pre>
<p>A base class subobject of a type can be declared stateless with the foll=
owing syntax:</p>
<pre><code>struct Data : public stateless Type
{
    ...
};</code></pre>
<p>In both cases, if <code>Type</code> is not an empty class, then this is =
a compile error. <code>stateless</code> cannot be applied to a base class w=
hich uses <code>virtual</code> inheritance.</p>
<p>Member subobjects that are arrayed cannot be declared with <code>statele=
ss</code> property. Variables which are not non-static data members cannot =
be declared with the stateless property.</p>
<p><code>stateless</code> cannot be applied to a member of a <code>union</c=
ode> class.</p>
<p>The stateless property can be conditional, based on a compile-time condi=
tion like <code>noexcept</code>. This is done as follows:</p>
<pre><code>template&lt;typename Alloc&gt;
struct DataBlock
{
    stateless(is_empty_v&lt;Alloc&gt;) Alloc a;
};</code></pre>
<p>In this case, <code>a</code> will be a stateless member only if its type=
 is empty. If the condition is false, then it is as if the stateless proper=
ty were not applied to the subobject.</p>
<p>To facilitate common use patterns, the <code>stateless(auto)</code> synt=
ax for subobjects shall be equivalent to <code>stateless(std::is_empty_v&lt=
;T&gt;)</code>, where <code>T</code> is the type of the subobject being dec=
lared.</p>
<h3 id=3D"stateless-behavior">Stateless behavior</h3>
<p>Stateless subobjects have no effect on the layout or size of their conta=
ining object. Similarly, the rules for standard layout types ignore the pre=
sence of any stateless subobjects. And thus, two classes can be layout comp=
atible even if they differ by the presence of stateless subobjects.</p>
<p>Stateless subobjects otherwise have the same effects on their containing=
 types as regular subobjects do. For example, a stateless subobject can cau=
se its container to not be trivially copyable, if it has a non-trivial copy=
 constructor (even though the object by definition has no state to copy).</=
p>
<p>The definition of &quot;empty class&quot; (per <code>std::is_empty</code=
>) must now be expanded. The rules for an empty class are:</p>
<ul>
<li>Non-union class.</li>
<li>No virtual functions.</li>
<li>No virtual base classes.</li>
<li>No non-empty base classes.</li>
<li>No non-stateless NSDMs.</li>
</ul>
<p>In all other ways, except where detailed below, a stateless subobject wo=
rks identically to a non-stateless one. Stateless subobjects are initialize=
d and destroyed just as if they were not stateless. Stateless subobjects un=
dergo copy and move construction and assignment along with all other subobj=
ects (though they will likely not be doing much). In particular, stateless =
subobjects are still members/base classes of the types that contain them, s=
o aggregate initialization of members (and bases) will still have to take t=
hem into account:</p>
<pre><code>struct foo {};

struct aggregate
{
  stateless foo f;
  int b;
};

//It may have no state, but `f` must still be initialized.
aggregate agg =3D {{}, 4};</code></pre>
<h3 id=3D"stateless-types">Stateless types</h3>
<p>The stateless property can be applied to (non-union) types as well:</p>
<pre><code>stateless class ClassName : BaseClasses
{
    ...
};</code></pre>
<p>The <code>stateless</code> keyword must be consistently associated with =
any forward declarations for stateless types.</p>
<pre><code>class ClassName;  //Not a stateless type.

stateless class ClassName  //Compiler error: you told me it wasn&#39;t stat=
eless before.
{
};</code></pre>
<p>And vice-versa.</p>
<p>A stateless class definition is ill-formed if the class is not empty (pe=
r the expanded rules for empty classes).</p>
<p>The size of a stateless class is not modified by being stateless. Theref=
ore, the size of a stateless class shall be no different from the size of a=
ny other empty class.</p>
<p>The statelessness of a type can be conditional, just like subobjects:</p=
>
<pre><code>template&lt;typename T&gt;
stateless(is_empty_v&lt;T&gt;) struct Foo : public T {};</code></pre>
<p>Here, <code>Foo</code> may or may not be stateless, depending on whether=
 <code>T</code> is empty. If the constant expression evaluates to <code>fal=
se</code>, then the class is not stateless.</p>
<p>To make certain conditions easier, there will be the <code>stateless(aut=
o)</code> syntax. When applied to a class declaration, <code>stateless(auto=
)</code> will cause the class to be stateless if the class is empty. If the=
 class is not empty, then the class will not be stateless.</p>
<p>When a stateless class is used to declare a direct subobject of another =
type, that subobject will be implicitly stateless. It is perfectly valid to=
 explicitly specify <code>stateless</code> on a member/base class of a stat=
eless type. If the conditions on the two <code>stateless</code> properties =
do not agree (one resolves to true and the other false), then the program i=
s il-formed.<a href=3D"#fn1" class=3D"footnoteRef" id=3D"fnref1"><sup>1</su=
p></a></p>
<p>Declaring an array of a stateless type as an NSDM is forbidden. Stateles=
s types may not be used as members of a union.</p>
<p>The standard library does not need to have a traits class to detect if a=
 type is stateless. A type with such a declaration can be used in any way t=
hat any type can, so <code>is_empty</code> is sufficient.</p>
<h3 id=3D"stateless-anonymous-types">Stateless anonymous types</h3>
<p>Statelessness can be applied to anonymous types as well:</p>
<pre><code>stateless(auto) struct
{
    Data d;
} varName;</code></pre>
<p>The <code>stateless</code> property applies to the struct declaration, n=
ot the variable. As such, <code>decltype(varName)</code> will be a stateles=
s type if <code>Data</code> is a stateless type. Such declarations can only=
 be made as non-static data members.</p>
<h2 id=3D"implementation-and-restrictions">Implementation and Restrictions<=
/h2>
<p>In a perfect world, the above would be the only restrictions on stateles=
s types. C++ of course is never perfect.</p>
<h3 id=3D"memory-locations">Memory locations</h3>
<p>In C++ as it currently stands, every object needs to have a memory locat=
ion. And two separate objects of unrelated types cannot have the <em>same</=
em> memory location.</p>
<p>Stateless subobojects effectively have to be able to break this rule. Th=
e memory location of a stateless subobject is more or less irrelevant. Sinc=
e the type is stateless, there is no independent state to access. So one in=
stance is functionally no different from another.<a href=3D"#fn2" class=3D"=
footnoteRef" id=3D"fnref2"><sup>2</sup></a></p>
<p>As such, the general idea is that a stateless subobject could have any a=
ddress within the storage of the object which contains it. This means that =
a stateless subobject can have the same address as any other subobject in i=
ts containing object's type.</p>
<p>This is not really an implementation problem, since stateless suboboject=
s by their very nature have no state to access. As such, the specific addre=
ss of their <code>this</code> pointer is irrelevant. What we need, standard=
-wise, is to modify the rules for accessing objects and aliasing to allow a=
 stateless subobject to have the same address as <em>any</em> other object.=
 Because stateless objects have no value to access, we may not even need to=
 change [basic.lval]/10.</p>
<p>The address of a stateless subobject can be any address within the stora=
ge of the object that contains it. The standard need not specify exactly wh=
ich address.</p>
<p>Implementation-wise, the difficulty will be in changing how types are la=
id out. That is, modifying ABIs to allow member subobjects that have no siz=
e and enforcing EBO even when it might otherwise have been forbidden.</p>
<p>The behavior of the <em>user</em> converting pointers/references between=
 two unrelated stateless subobjects should still be undefined. We just need=
 rules to allow stateless subobjects to be assigned a memory location at th=
e discretion of the compiler, which may not be unique from other unrelated =
objects.</p>
<h3 id=3D"stateless-arrays">Stateless arrays</h3>
<p>This design expressly forbids the declaration of stateless member subobj=
ects that are arrayed. The reason for this has to do with pointer arithmeti=
c.</p>
<p>In C++, the following should be perfectly valid for any type <code>T</co=
de>, regarldess of where the array of <code>T</code> is declared:</p>
<pre><code>T t[5];
T *first =3D &amp;t[0];
T *last =3D first + 5;
assert(sizeof(T) * 5 =3D=3D last - first);</code></pre>
<p>The whole point of a stateless subobject is that it does not take up spa=
ce within another type. If the array above were a member of another type, t=
his code still ought to work. But, since <code>sizeof(T)</code> is non-zero=
, that means that those values have to take up space somewhere. Each pointe=
r has to be valid.</p>
<p>Under non-array conditions, the pointer to a stateless subobject could a=
lways have the same address as its container (recursively, to the last non-=
stateless container). Adding 1 to any such pointer will still be a valid ad=
dress; this is required because any object can be considered an array of 1 =
value ([expr.add]/4). If the containing class is an empty class with a size=
 of 1, then adding one to a stateless member's pointer is no less valid tha=
n adding 1 to the container's address.</p>
<p>When dealing with an array, this is not necessarily the case. If the sta=
teless array has a count larger than 1, and it is contained in an empty cla=
ss, there is no guarantee that adding a number larger than 1 will result in=
 a valid address for the purposes of iteration.</p>
<p>Several alternatives were considered:</p>
<ol style=3D"list-style-type: decimal">
<li><p>Declare that <code>sizeof</code> for stateless subobjects is zero. I=
 am not nearly familiar enough with the C++ standard to know the level of h=
orrors that this would unleash, but I can imagine that it's very bad. It wo=
uld also make it impossible to have a distinction between stateless subobje=
cts and stateless types, as the <code>sizeof</code> can be applied to a poi=
nter to the object, which cannot know if the object it points to is statele=
ss.</p></li>
<li><p>Declare that stateless subobjects which are arrayed will still take =
up space as though they were not declared <code>stateless</code>.</p></li>
<li><p>Forbid declaring arrays of stateless subobjects altogether.</p></li>
</ol>
<p>Option 1 is probably out due to various potential issues. #2 seems tempt=
ing, but it makes the use of <code>stateless T arr[4];</code> something of =
a lie. Earlier designs used #3, then switched to #2. But the current design=
 goes back to #3 for an important reason.</p>
<p>In the current design, it is the <em>use</em> of a type which is statele=
ss. Types can be declared stateless as well, but this really only means tha=
t all uses of them to declare objects will implicitly be stateless. So this=
 restricts how the type may be used, but not the semantics of it.</p>
<p>Because statelessness can be applied to any empty class at its point of =
use, if a user wants to be able to use an empty class in a non-stateless wa=
y, then they simply do not declare the class to be stateless.</p>
<p>And therefore, if you declare a class to be stateless, you truly intend =
for it to only be used as a subobject of another type. This would be useful=
 for a CRTP base class, for example, where it is a logical error to create =
an object of the class which is not a base class.</p>
<h3 id=3D"trivial-copyability">Trivial copyability</h3>
<p>Trivial copyability is another area that can be problematic with statele=
ss subobjects. We explicitly forbid trivial copying into a base class subob=
ject of another class ([basic.types]/2).</p>
<p>Similarly, we must explicitly forbid trivial copying into stateless subo=
bojects. Trivial copying <em>from</em> a stateless subobject should be OK. =
Though this is only &quot;OK&quot; in the sense that the program is not ill=
-formed or that there us undefined behavior. The value copied is undefined,=
 but that doesn't matter, since you could only ever use that value to initi=
alize a type that is layout compatible with an empty class. Namely, another=
 empty class. And empty classes have no value.</p>
<h3 id=3D"offsetof">offsetof</h3>
<p><code>offsetof</code> will obviously not be affected by stateless subobj=
ect members of another type. However, if <code>offsetof</code> is applied t=
o a stateless subobject, what is the result?</p>
<p>I would suggest that this either be undefined or 0.</p>
<h1 id=3D"potential-issues">Potential issues</h1>
<h2 id=3D"the-unknown">The Unknown</h2>
<p>One of the most difficult aspects of dealing with any form of stateless =
type system is that it represents something that is very new and very compl=
icated for C++ to deal with. As such, the wording for this needs to be quit=
e precise and comprehensive, lest we introduce subtle bugs into the standar=
d.</p>
<p>A good spec doctor needs to be involved with the standardization of this=
 feature.</p>
<h1 id=3D"alternative-designs-explored">Alternative Designs Explored</h1>
<p>There has been many alternatives towards achieving the same ends. Every =
such alternative has to deal with 2 fundamental rules of the C++ object mod=
el:</p>
<ol style=3D"list-style-type: decimal">
<li>Objects are defined by a region of storage.</li>
<li>Two different object instances have different regions of storage.</li>
</ol>
<p>This current proposal focuses on avoiding changes to rule #1. Stateless =
subobjects in this proposal still have a non-zero size. Instead, changes to=
 rule #2 are made to permit stateless objects to work.</p>
<p>Other alternatives take a different approach to dealing with these rules=
..</p>
<h2 id=3D"magic-standard-library-wrapper-type">Magic standard library wrapp=
er type</h2>
<p><a href=3D"https://groups.google.com/a/isocpp.org/d/msg/std-proposals/sA=
dqngl8pew/xCjHCLpuAAAJ">This idea</a> is focused on just the specific case =
of having empty classes potentially take up no space in their containing cl=
asses.</p>
<p>It would essentially declare a standard library type that is, in the con=
text of this proposal, something like this:</p>
<pre><code>template&lt;typename T&gt;
stateless(is_empty_v&lt;T&gt;) struct allow_zero_size : public T {...};</co=
de></pre>
<p>It is a wrapper which, when used as an NSDM, will not take up any space =
in its containing object if the given type is empty. And if it is not, then=
 it will.</p>
<p>The theoretical idea behind this is that it doesn't require new syntax. =
And in that proposal, <code>allow_zero_size</code> would not be forbidden f=
rom being in arrays or any of the other forbearances that this proposal for=
bids stateless types from.</p>
<p>This makes the behavior of such a type rather more difficult to specify.=
 The standard would still need to have changes to allow subobojects which t=
ake up no space to work, since users have to be able to get pointers/refere=
nces to them and the like. Once that work is done, exactly how you specify =
that a subobject takes up no space does not really matter.</p>
<h1 id=3D"acknowledgments">Acknowledgments</h1>
<p>From the C++ Future Discussions forum:</p>
<ul>
<li>Avi Kivity</li>
<li>A. Jo=C3=ABl Lamotte, who's original thread on <a href=3D"https://group=
s.google.com/a/isocpp.org/d/msg/std-proposals/u35GIuJECcQ/Yorc58iiBwAJ">Inl=
ine Classes</a> was the seed for this idea.</li>
<li>Vicente J. Botet Escriba</li>
<li>Matt Calabrese</li>
<li>Andrew Tomazos</li>
<li>Matthew Woehlke</li>
</ul>
<div class=3D"footnotes">
<hr />
<ol>
<li id=3D"fn1"><p>It may be reasonable to use the logical <code>or</code> b=
etween the two, instead of failing on a mis-match.<a href=3D"#fnref1">=E2=
=86=A9</a></p></li>
<li id=3D"fn2"><p>Yes, it is be possible for an otherwise empty type to use=
 its own <code>this</code> pointer as its state. This could be used to regi=
ster itself with some global system or perform some other side-effect. The =
current rules ensure, even with EBO, that an empty object instance will alw=
ays have a distinct <code>this</code> pointer from any other instance of th=
at type. However, such types would be inappropriate to use as stateless typ=
es, since they are not logically stateless. Further, I find it highly unlik=
ely that such code is sufficiently widespread to be much of a problem. It w=
ould be better for makers of such classes to simply declare an unused membe=
r of type <code>char</code>, to prevent themselves from being considered em=
pty.<a href=3D"#fnref2">=E2=86=A9</a></p></li>
</ol>
</div>
</body>
</html>

------=_Part_4960_1290977361.1467944202609
Content-Type: text/x-markdown; charset=UTF-8; name="Stateless Subobjects.md"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename="Stateless Subobjects.md"
X-Attachment-Id: e15c613d-44e9-4d76-a97f-e7704af85ab0
Content-ID: <e15c613d-44e9-4d76-a97f-e7704af85ab0>

% Stateless Subobjects and Types, v0.7
%
% July 7, 2016

This proposal specifies the ability to declare member and base class subobj=
ects which do not take up space in the objects they are contained within. I=
t also allows the user to define classes which will always be used in such =
a fashion.

# Motivation and Scope

An object is stateless, conceptually speaking, if it has no non-static data=
 members. As such, the state of any particular instance is no different fro=
m another. Because of this, there is no conceptual reason why a stateless o=
bject needs to have a region of storage associated with it.

In C++, a class would be stateless if it has no non-static data members (NS=
DMs) and all of its base classes likewise are stateless as well. `is_empty_=
v` qualifies as a useful test, but technically other classes could qualify =
as well (those with virtual members/base classes).

There are many times when a user wants to use a class that the user provide=
s, but the class may or may not be logically stateless. If it is stateless,=
 then it would be best if the class which uses it would not grow in size si=
mply due to the presence of the stateless subobject. After all, a conceptua=
lly stateless object does not need to take up space to do its job.

To avoid this, users will frequently use standard layout rules and the empt=
y base optimization to allow them to have access to a stateless subobject:

=09template<typename Alloc>
=09struct DataBlock : public Alloc
=09{
=09};

In this case, if `Alloc` is empty, then so long as `DataBlock` follows stan=
dard layout rules, the user is guaranteed that `DataBlock` is no larger tha=
n it would have been if `Alloc` were not empty. Even if it does not follow =
standard layout, the compiler is free to optimize the empty base `Alloc` aw=
ay.

There are of course problems with such a use. If `Alloc` is not empty (and =
`DataBlock` does not require that it is), and `Alloc` declares a virtual fu=
nction, it is possible that `DataBlock<Alloc>` will accidentally override t=
hat virtual function. Or not quite override it and cause a compile error. W=
hereas if `Alloc` were a non-static data member, this could easily be avoid=
ed.

Equally importantly, this use of `Alloc` is simply not how a user would nat=
urally write this class. Inheritance is supposed to model an "is a" relatio=
nship. Yet conceptually, `DataBlock` is not an `Alloc`; it *has* an `Alloc`=
.. `DataBlock` uses inheritance, not to model a relationship, but as an opti=
mization tool, to keep the class from growing unnecessarily.

The intent of this proposal is to permit, among other things, classes like =
`DataBlock` to declare `Alloc` as a non-static data member. And if `Alloc` =
is empty, then `DataBlock` can use syntax to make the `Alloc` NSDM take up =
no space in `DataBlock`'s layout.

This would also be recursive, so that if `Alloc` had no NSDMs, and `DataBlo=
ck<Alloc>` had no NSDMs besides the `Alloc` member, then `DataBlock<Alloc>`=
 would also be considered an empty type. And therefore, some other type cou=
ld use it in a stateless fashion.

# Design

We define two concepts: stateless subobjects and stateless classes. A state=
less class is really just shorthand for the former; it declares that instan=
ces of the class can only be created as stateless subobjects of some other =
type.

Note: The following syntax is entirely preliminary. This proposal is not we=
dded to the idea of introducing a new keyword or somesuch. This syntax is h=
ere simply for the sake of understanding how the functionality should gener=
ally be specified. The eventual syntax could be a contextual keyword like `=
final` and `override`, or it could be something else.

### Stateless subobojects

A non-static data member subobject of a type can be declared stateless with=
 the following syntax:

=09struct Data
=09{
=09=09stateless Type val;
=09};
=09
A base class subobject of a type can be declared stateless with the followi=
ng syntax:

=09struct Data : public stateless Type
=09{
=09=09...
=09};

In both cases, if `Type` is not an empty class, then this is a compile erro=
r. `stateless` cannot be applied to a base class which uses `virtual` inher=
itance.

Member subobjects that are arrayed cannot be declared with `stateless` prop=
erty. Variables which are not non-static data members cannot be declared wi=
th the stateless property.

`stateless` cannot be applied to a member of a `union` class.

The stateless property can be conditional, based on a compile-time conditio=
n like `noexcept`. This is done as follows:

=09template<typename Alloc>
=09struct DataBlock
=09{
=09=09stateless(is_empty_v<Alloc>) Alloc a;
=09};

In this case, `a` will be a stateless member only if its type is empty. If =
the condition is false, then it is as if the stateless property were not ap=
plied to the subobject.

To facilitate common use patterns, the `stateless(auto)` syntax for subobje=
cts shall be equivalent to `stateless(std::is_empty_v<T>)`, where `T` is th=
e type of the subobject being declared.

### Stateless behavior

Stateless subobjects have no effect on the layout or size of their containi=
ng object. Similarly, the rules for standard layout types ignore the presen=
ce of any stateless subobjects. And thus, two classes can be layout compati=
ble even if they differ by the presence of stateless subobjects.

Stateless subobjects otherwise have the same effects on their containing ty=
pes as regular subobjects do. For example, a stateless subobject can cause =
its container to not be trivially copyable, if it has a non-trivial copy co=
nstructor (even though the object by definition has no state to copy).

The definition of "empty class" (per `std::is_empty`) must now be expanded.=
 The rules for an empty class are:

* Non-union class.
* No virtual functions.
* No virtual base classes.
* No non-empty base classes.
* No non-stateless NSDMs.

In all other ways, except where detailed below, a stateless subobject works=
 identically to a non-stateless one. Stateless subobjects are initialized a=
nd destroyed just as if they were not stateless. Stateless subobjects under=
go copy and move construction and assignment along with all other subobject=
s (though they will likely not be doing much). In particular, stateless sub=
objects are still members/base classes of the types that contain them, so a=
ggregate initialization of members (and bases) will still have to take them=
 into account:

=09struct foo {};

=09struct aggregate
=09{
=09  stateless foo f;
=09  int b;
=09};

=09//It may have no state, but `f` must still be initialized.
=09aggregate agg =3D {{}, 4};

### Stateless types

The stateless property can be applied to (non-union) types as well:

=09stateless class ClassName : BaseClasses
=09{
=09=09...
=09};

The `stateless` keyword must be consistently associated with any forward de=
clarations for stateless types.

=09class ClassName;  //Not a stateless type.

=09stateless class ClassName  //Compiler error: you told me it wasn't state=
less before.
=09{
=09};

And vice-versa.

A stateless class definition is ill-formed if the class is not empty (per t=
he expanded rules for empty classes).

The size of a stateless class is not modified by being stateless. Therefore=
, the size of a stateless class shall be no different from the size of any =
other empty class.

The statelessness of a type can be conditional, just like subobjects:

=09template<typename T>
=09stateless(is_empty_v<T>) struct Foo : public T {};
=09
Here, `Foo` may or may not be stateless, depending on whether `T` is empty.=
 If the constant expression evaluates to `false`, then the class is not sta=
teless.

To make certain conditions easier, there will be the `stateless(auto)` synt=
ax. When applied to a class declaration, `stateless(auto)` will cause the c=
lass to be stateless if the class is empty. If the class is not empty, then=
 the class will not be stateless.

When a stateless class is used to declare a direct subobject of another typ=
e, that subobject will be implicitly stateless. It is perfectly valid to ex=
plicitly specify `stateless` on a member/base class of a stateless type. If=
 the conditions on the two `stateless` properties do not agree (one resolve=
s to true and the other false), then the program is il-formed.[^1]

Declaring an array of a stateless type as an NSDM is forbidden. Stateless t=
ypes may not be used as members of a union.

The standard library does not need to have a traits class to detect if a ty=
pe is stateless. A type with such a declaration can be used in any way that=
 any type can, so `is_empty` is sufficient.

### Stateless anonymous types

Statelessness can be applied to anonymous types as well:

=09stateless(auto) struct
=09{
=09=09Data d;
=09} varName;

The `stateless` property applies to the struct declaration, not the variabl=
e. As such, `decltype(varName)` will be a stateless type if `Data` is a sta=
teless type. Such declarations can only be made as non-static data members.

## Implementation and Restrictions

In a perfect world, the above would be the only restrictions on stateless t=
ypes. C++ of course is never perfect.

### Memory locations

In C++ as it currently stands, every object needs to have a memory location=
.. And two separate objects of unrelated types cannot have the *same* memory=
 location.

Stateless subobojects effectively have to be able to break this rule. The m=
emory location of a stateless subobject is more or less irrelevant. Since t=
he type is stateless, there is no independent state to access. So one insta=
nce is functionally no different from another.[^2]

As such, the general idea is that a stateless subobject could have any addr=
ess within the storage of the object which contains it. This means that a s=
tateless subobject can have the same address as any other subobject in its =
containing object's type.

This is not really an implementation problem, since stateless subobojects b=
y their very nature have no state to access. As such, the specific address =
of their `this` pointer is irrelevant. What we need, standard-wise, is to m=
odify the rules for accessing objects and aliasing to allow a stateless sub=
object to have the same address as *any* other object. Because stateless ob=
jects have no value to access, we may not even need to change [basic.lval]/=
10.

The address of a stateless subobject can be any address within the storage =
of the object that contains it. The standard need not specify exactly which=
 address.

Implementation-wise, the difficulty will be in changing how types are laid =
out. That is, modifying ABIs to allow member subobjects that have no size a=
nd enforcing EBO even when it might otherwise have been forbidden.

The behavior of the *user* converting pointers/references between two unrel=
ated stateless subobjects should still be undefined. We just need rules to =
allow stateless subobjects to be assigned a memory location at the discreti=
on of the compiler, which may not be unique from other unrelated objects.

### Stateless arrays

This design expressly forbids the declaration of stateless member subobject=
s that are arrayed. The reason for this has to do with pointer arithmetic.

In C++, the following should be perfectly valid for any type `T`, regarldes=
s of where the array of `T` is declared:

=09T t[5];
=09T *first =3D &t[0];
=09T *last =3D first + 5;
=09assert(sizeof(T) * 5 =3D=3D last - first);

The whole point of a stateless subobject is that it does not take up space =
within another type. If the array above were a member of another type, this=
 code still ought to work. But, since `sizeof(T)` is non-zero, that means t=
hat those values have to take up space somewhere. Each pointer has to be va=
lid.

Under non-array conditions, the pointer to a stateless subobject could alwa=
ys have the same address as its container (recursively, to the last non-sta=
teless container). Adding 1 to any such pointer will still be a valid addre=
ss; this is required because any object can be considered an array of 1 val=
ue ([expr.add]/4). If the containing class is an empty class with a size of=
 1, then adding one to a stateless member's pointer is no less valid than a=
dding 1 to the container's address.

When dealing with an array, this is not necessarily the case. If the statel=
ess array has a count larger than 1, and it is contained in an empty class,=
 there is no guarantee that adding a number larger than 1 will result in a =
valid address for the purposes of iteration.

Several alternatives were considered:

1. Declare that `sizeof` for stateless subobjects is zero. I am not nearly =
familiar enough with the C++ standard to know the level of horrors that thi=
s would unleash, but I can imagine that it's very bad. It would also make i=
t impossible to have a distinction between stateless subobjects and statele=
ss types, as the `sizeof` can be applied to a pointer to the object, which =
cannot know if the object it points to is stateless.

2. Declare that stateless subobjects which are arrayed will still take up s=
pace as though they were not declared `stateless`.

3. Forbid declaring arrays of stateless subobjects altogether.

Option 1 is probably out due to various potential issues. #2 seems tempting=
, but it makes the use of `stateless T arr[4];` something of a lie. Earlier=
 designs used #3, then switched to #2. But the current design goes back to =
#3 for an important reason.

In the current design, it is the *use* of a type which is stateless. Types =
can be declared stateless as well, but this really only means that all uses=
 of them to declare objects will implicitly be stateless. So this restricts=
 how the type may be used, but not the semantics of it.

Because statelessness can be applied to any empty class at its point of use=
, if a user wants to be able to use an empty class in a non-stateless way, =
then they simply do not declare the class to be stateless.

And therefore, if you declare a class to be stateless, you truly intend for=
 it to only be used as a subobject of another type. This would be useful fo=
r a CRTP base class, for example, where it is a logical error to create an =
object of the class which is not a base class.

### Trivial copyability

Trivial copyability is another area that can be problematic with stateless =
subobjects. We explicitly forbid trivial copying into a base class subobjec=
t of another class ([basic.types]/2).

Similarly, we must explicitly forbid trivial copying into stateless suboboj=
ects. Trivial copying *from* a stateless subobject should be OK. Though thi=
s is only "OK" in the sense that the program is not ill-formed or that ther=
e us undefined behavior. The value copied is undefined, but that doesn't ma=
tter, since you could only ever use that value to initialize a type that is=
 layout compatible with an empty class. Namely, another empty class. And em=
pty classes have no value.

### offsetof

`offsetof` will obviously not be affected by stateless subobject members of=
 another type. However, if `offsetof` is applied to a stateless subobject, =
what is the result?

I would suggest that this either be undefined or 0.

# Potential issues

## The Unknown

One of the most difficult aspects of dealing with any form of stateless typ=
e system is that it represents something that is very new and very complica=
ted for C++ to deal with. As such, the wording for this needs to be quite p=
recise and comprehensive, lest we introduce subtle bugs into the standard.

A good spec doctor needs to be involved with the standardization of this fe=
ature.

# Alternative Designs Explored

There has been many alternatives towards achieving the same ends. Every suc=
h alternative has to deal with 2 fundamental rules of the C++ object model:

1. Objects are defined by a region of storage.
2. Two different object instances have different regions of storage.

This current proposal focuses on avoiding changes to rule #1. Stateless sub=
objects in this proposal still have a non-zero size. Instead, changes to ru=
le #2 are made to permit stateless objects to work.

Other alternatives take a different approach to dealing with these rules.

## Magic standard library wrapper type

[This idea](https://groups.google.com/a/isocpp.org/d/msg/std-proposals/sAdq=
ngl8pew/xCjHCLpuAAAJ) is focused on just the specific case of having empty =
classes potentially take up no space in their containing classes.

It would essentially declare a standard library type that is, in the contex=
t of this proposal, something like this:

=09template<typename T>
=09stateless(is_empty_v<T>) struct allow_zero_size : public T {...};

It is a wrapper which, when used as an NSDM, will not take up any space in =
its containing object if the given type is empty. And if it is not, then it=
 will.

The theoretical idea behind this is that it doesn't require new syntax. And=
 in that proposal, `allow_zero_size` would not be forbidden from being in a=
rrays or any of the other forbearances that this proposal forbids stateless=
 types from.

This makes the behavior of such a type rather more difficult to specify. Th=
e standard would still need to have changes to allow subobojects which take=
 up no space to work, since users have to be able to get pointers/reference=
s to them and the like. Once that work is done, exactly how you specify tha=
t a subobject takes up no space does not really matter.

# Acknowledgments

From the C++ Future Discussions forum:

* Avi Kivity
* A. Jo=C3=ABl Lamotte, who's original thread on [Inline Classes](https://g=
roups.google.com/a/isocpp.org/d/msg/std-proposals/u35GIuJECcQ/Yorc58iiBwAJ)=
 was the seed for this idea.
* Vicente J. Botet Escriba
* Matt Calabrese
* Andrew Tomazos
* Matthew Woehlke


[^1]: It may be reasonable to use the logical `or` between the two, instead=
 of failing on a mis-match.

[^2]: Yes, it is be possible for an otherwise empty type to use its own `th=
is` pointer as its state. This could be used to register itself with some g=
lobal system or perform some other side-effect. The current rules ensure, e=
ven with EBO, that an empty object instance will always have a distinct `th=
is` pointer from any other instance of that type. However, such types would=
 be inappropriate to use as stateless types, since they are not logically s=
tateless. Further, I find it highly unlikely that such code is sufficiently=
 widespread to be much of a problem. It would be better for makers of such =
classes to simply declare an unused member of type `char`, to prevent thems=
elves from being considered empty.
------=_Part_4960_1290977361.1467944202609--

.


Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Wed, 13 Jul 2016 04:03:41 -0700 (PDT)
Raw View
------=_Part_1643_167508531.1468407822489
Content-Type: multipart/alternative;
 boundary="----=_Part_1644_205309917.1468407822489"

------=_Part_1644_205309917.1468407822489
Content-Type: text/plain; charset=UTF-8

It seems to me that by requiring that the type of the variable being
declared *stateless* really is empty you prevent your new feature from
being used in maybe the most common use case exemplified by the container *Alloc
*type. What's needed there is a potentially zero-sized member in case the
Alloc class is stateless, but which takes up as much space as needed if it
is not.

I commend you for pointing out that even classes with virtual methods can
be empty, but maybe your paper should elaborate a little on why: You think
of such an object as containing only a vtbl pointer but as it is a by-value
member of its containing object you don't need the vtbl pointer as you know
what it points to for each method anyway.

Your idea of allowing a class declaration to be declared stateless is scary
as it removes the declaration of the statelessness from the usage. Now you
can declare a std::vector<T> with a stateless T and, well, it is hard to
tell if this would work. If sizeof(T) is 1 for a stateless T it could but
would waste heap memory. As long as the stateless property is on the
variable the code accessing the variable can work with the restrictions
that this qualifier introduces.

I don't see the problem with array iteration that you state " If the
stateless array has a count larger than 1, and it is contained in an empty
class, there is no guarantee that adding a number larger than 1 will result
in a valid address for the purposes of iteration."
The address is going to be just as valid as for any iteration. Yes, the
address can point to memory that would cause an access violation if
accessed, but there is no state to access there anyway, so doing so
deserves an access violation. What could possibly happen is that if you
declare a very large array of zero sized objects the address could wrap
around causing loops with < end conditions to stop immediately. Is this
what you mean? I would say that this case is arcane enough to let through
with a recommendation: Don't use < tests on loop pointers when iterating
over stateless objects. (Here again is a difference between a stateless
variable and a stateless class: if stateless claesses are allowed this has
to be extended to: Don't use < tests in loops in template code). In any
case, as you mention: The this pointer for any method call inside the loop
body would not care if the address was actually outside the memory area (0
bytes) allocated for the array... it will not use the this pointer anyway.

Oops: While writting the previous clause I noted that your assumption that
types with virtual methods are ok as stateless is false: If the
implementation of a virtual method that you call directly by compile time
lookup of the vtbl calls another virtual method this will be done using a
regular virtual call, and thus it will need the vtbl that was optimized
away!


Den fredag 8 juli 2016 kl. 04:16:42 UTC+2 skrev Nicol Bolas:
>
> A while back, I came up with a proposal for stateless types, as well as
> inner classes and mixin support. At the time, I thought that all three
> ideas built on one another, such that only providing one of them would not
> be a particularly worthwhile feature. Since then, I've had a re-evaluation
> of that notion.
>
> So here is what I currently think in terms of just stateless stuff. The
> proposal is available in HTML and Markdown formats.
>
> A quick overview:
>
> * You can declare that a empty type which is used as a subobject of a
> class is stateless (taking up no space in the layout). Stateless subobjects
> behave like regular objects where possible. This works for both members
> *and* base classes; people keep forgetting that EBO is *optional* if the
> class isn't standard layout.
> * You can declare that a type will be used in a stateless fashion whenever
> it is declared as a subobject of another type. It can be used normally in
> non-stateless ways, but it must conform to the requirements of stateless
> subobject (ie: the class must be empty).
> * You can condition either kind of declaration on a constant expression,
> like `noexcept` conditions.
>

--
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/d0376abc-e652-4d7b-a7f5-4c8ea1ba49fb%40isocpp.org.

------=_Part_1644_205309917.1468407822489
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">It seems to me that by requiring that the type of the vari=
able being declared <i>stateless</i> really is empty you prevent your new f=
eature from being used in maybe the most common use case exemplified by the=
 container <i>Alloc </i>type. What&#39;s needed there is a potentially zero=
-sized member in case the Alloc class is stateless, but which takes up as m=
uch space as needed if it is not.<div><br></div><div>I commend you for poin=
ting out that even classes with virtual methods can be empty, but maybe you=
r paper should elaborate a little on why: You think of such an object as co=
ntaining only a vtbl pointer but as it is a by-value member of its containi=
ng object you don&#39;t need the vtbl pointer as you know what it points to=
 for each method anyway.</div><div><br></div><div>Your idea of allowing a c=
lass declaration to be declared stateless is scary as it removes the declar=
ation of the statelessness from the usage. Now you can declare a std::vecto=
r&lt;T&gt; with a stateless T and, well, it is hard to tell if this would w=
ork. If sizeof(T) is 1 for a stateless T it could but would waste heap memo=
ry. As long as the stateless property is on the variable the code accessing=
 the variable can work with the restrictions that this qualifier introduces=
..</div><div><br></div><div>I don&#39;t see the problem with array iteration=
 that you state &quot;<span style=3D"color: rgb(0, 0, 0); font-family: &quo=
t;Times New Roman&quot;; font-size: medium;">=C2=A0If the stateless array h=
as a count larger than 1, and it is contained in an empty class, there is n=
o guarantee that adding a number larger than 1 will result in a valid addre=
ss for the purposes of iteration.&quot;</span></div><div>The address is goi=
ng to be just as valid as for any iteration. Yes, the address can point to =
memory that would cause an access violation if accessed, but there is no st=
ate to access there anyway, so doing so deserves an access violation. What =
could possibly happen is that if you declare a very large array of zero siz=
ed objects the address could wrap around causing loops with &lt; end condit=
ions to stop immediately. Is this what you mean? I would say that this case=
 is arcane enough to let through with a recommendation: Don&#39;t use &lt; =
tests on loop pointers when iterating over stateless objects. (Here again i=
s a difference between a stateless variable and a stateless class: if state=
less claesses are allowed this has to be extended to: Don&#39;t use &lt; te=
sts in loops in template code). In any case, as you mention: The this point=
er for any method call inside the loop body would not care if the address w=
as actually outside the memory area (0 bytes) allocated for the array... it=
 will not use the this pointer anyway.</div><div><br></div><div>Oops: While=
 writting the previous clause I noted that your assumption that types with =
virtual methods are ok as stateless is false: If the implementation of a vi=
rtual method that you call directly by compile time lookup of the vtbl call=
s another virtual method this will be done using a regular virtual call, an=
d thus it will need the vtbl that was optimized away!</div><div><div><br><b=
r>Den fredag 8 juli 2016 kl. 04:16:42 UTC+2 skrev Nicol Bolas:<blockquote c=
lass=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px=
 #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">A while back, I came up wi=
th a proposal for stateless types, as well as inner classes and mixin suppo=
rt. At the time, I thought that all three ideas built on one another, such =
that only providing one of them would not be a particularly worthwhile feat=
ure. Since then, I&#39;ve had a re-evaluation of that notion.<br><br>So her=
e is what I currently think in terms of just stateless stuff. The proposal =
is available in HTML and Markdown formats.<br><br>A quick overview:<br><br>=
* You can declare that a empty type which is used as a subobject of a class=
 is stateless (taking up no space in the layout). Stateless subobjects beha=
ve like regular objects where possible. This works for both members <i>and<=
/i> base classes; people keep forgetting that EBO is <i>optional</i> if the=
 class isn&#39;t standard layout.<br>* You can declare that a type will be =
used in a stateless fashion whenever it is declared as a subobject of anoth=
er type. It can be used normally in non-stateless ways, but it must conform=
 to the requirements of stateless subobject (ie: the class must be empty).<=
br>* You can condition either kind of declaration on a constant expression,=
 like `noexcept` conditions.<br></div></blockquote></div></div></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/d0376abc-e652-4d7b-a7f5-4c8ea1ba49fb%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/d0376abc-e652-4d7b-a7f5-4c8ea1ba49fb=
%40isocpp.org</a>.<br />

------=_Part_1644_205309917.1468407822489--

------=_Part_1643_167508531.1468407822489--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Wed, 13 Jul 2016 07:20:22 -0700 (PDT)
Raw View
------=_Part_600_1606007593.1468419622508
Content-Type: multipart/alternative;
 boundary="----=_Part_601_1437900788.1468419622508"

------=_Part_601_1437900788.1468419622508
Content-Type: text/plain; charset=UTF-8

On Wednesday, July 13, 2016 at 7:03:42 AM UTC-4, Bengt Gustafsson wrote:
>
> It seems to me that by requiring that the type of the variable being
> declared *stateless* really is empty you prevent your new feature from
> being used in maybe the most common use case exemplified by the container *Alloc
> *type. What's needed there is a potentially zero-sized member in case the
> Alloc class is stateless, but which takes up as much space as needed if it
> is not.
>

I called that specific case out as an example:

template<typename Alloc>
struct DataBlock
{
    stateless(is_empty_v<Alloc>) Alloc a;
};

`a` will take up no space if `Alloc` is empty. Also, you could use
`stateless(auto)` instead of the explicit `is_empty_v` test.

This allows you to make a distinction between "Make this object stateless
where possible" and "If this type is not empty, then that's an error."
While the former is useful, the latter is also quite useful. After all, if
your type needs to be empty, and you're including a bunch of other member
types, you want to make sure nobody breaks your type's rules by
accidentally adding an NSDM or something.

That is:

struct OtherType
{
  stateless First f;
  Second s; //Oops, forgot to declare that stateless.
};

struct MyType
{
  stateless OtherType o;
};

`MyType` should be *guaranteed* to be empty, just as if you had declared no
members at all. If `OtherType` doesn't play along, then there clearly ought
to be a compile error.

I commend you for pointing out that even classes with virtual methods can
> be empty, but maybe your paper should elaborate a little on why: You think
> of such an object as containing only a vtbl pointer but as it is a by-value
> member of its containing object you don't need the vtbl pointer as you know
> what it points to for each method anyway.
>

The Motivation and Scope section didn't exclude virtual types, but that was
because they are *logically* empty. The Design section made it perfectly
clear that types with virtual functions or members are not considered empty
and thus are not eligible to be used statelessly.

Your idea of allowing a class declaration to be declared stateless is scary
> as it removes the declaration of the statelessness from the usage. Now you
> can declare a std::vector<T> with a stateless T and, well, it is hard to
> tell if this would work. If sizeof(T) is 1 for a stateless T it could but
> would waste heap memory.
>

Looking back at the proposal, I don't think I made my intentions with
stateless types sufficiently explicit.

With two exceptions that I'll get to in a moment, a stateless type can be
used exactly like any other type. You can heap allocate them, use placement
new, etc. When you use a stateless type to directly create an object in a
way that cannot have `stateless` applied (stack variables, `new`, etc),
then the object behaves just like any empty type. So if you use
`std::allocate<Stateless>::allocate(5)`, you will get an array of 5 empty
objects. A vector of stateless types is no different from a vector of empty
types.

However, if you use a stateless type to declare an object for which
`stateless` *can* be applied (direct NSDM or base class of a non-union
class type), then `stateless` is implicitly added to that declaration. So a
stateless type declaration is simply saying that the objects created from
it will be stateless wherever possible. And that is only possible as a
direct subobject of a non-union class type.

Remember: the goal of this proposal is *not* to allow zero-sized objects
(and arrays). The goal is to make empty subobjects be able to not affect
the layout of the type. A `vector<T>` does not create its Ts as subobjects
of a type. So the fact that `T` is a stateless type is irrelevant.

When it comes to stateless types, there are really only two choices for
what should happen if you use them in a non-stateless way. Either it is an
explicit error, or it is legal and behaves as it normally would (ie: like
any empty type).

My proposal suggests the latter. Earlier versions preferred the former, but
that plays extreme havoc with using stateless types in template code. The
most obvious example being `tuple`; if you give it a stateless type, it
should still be able to work. But if you use option 1, there is no way it
possibly could, since `tuple` implementations often rely on placement new
and so forth. And stateless types would be forbidden from being used by
placement new. Oh sure, with option 2 there's no guarantee that a tuple
implementation will actually make the contained value *stateless*. But at
least the code would compile and function adequately.

My proposal makes two exceptions for option 2: stateless types as NSDM
arrays, and stateless types in unions. You could allow stateless types to
be in unions and NSDM arrays. However, their behavior would *not* be
stateless.

The reason to forbid them is mainly sanity. A user who doesn't understand
the complexities of C++ may well expect an NSDM array of stateless types to
be a stateless array. But it won't; it'll just be an array of empty
classes, and the size of the containing type would be adjusted
appropriately. By contrast, if you declare a stack variable of a stateless
type, the user has no easy (standard-provided) way to tell if this actually
takes up room on the stack. Whereas `sizeof` is very much standard-provided.

I'm open to being convinced otherwise however. Particularly with template
code.


> As long as the stateless property is on the variable the code accessing
> the variable can work with the restrictions that this qualifier introduces.
>
I don't see the problem with array iteration that you state " If the
> stateless array has a count larger than 1, and it is contained in an empty
> class, there is no guarantee that adding a number larger than 1 will result
> in a valid address for the purposes of iteration."
> The address is going to be just as valid as for any iteration. Yes, the
> address can point to memory that would cause an access violation if
> accessed, but there is no state to access there anyway, so doing so
> deserves an access violation. What could possibly happen is that if you
> declare a very large array of zero sized objects the address could wrap
> around causing loops with < end conditions to stop immediately. Is this
> what you mean? I would say that this case is arcane enough to let through
> with a recommendation: Don't use < tests on loop pointers when iterating
> over stateless objects. (Here again is a difference between a stateless
> variable and a stateless class: if stateless claesses are allowed this has
> to be extended to: Don't use < tests in loops in template code). In any
> case, as you mention: The this pointer for any method call inside the loop
> body would not care if the address was actually outside the memory area (0
> bytes) allocated for the array... it will not use the this pointer anyway.
>

As far as C++ is concerned, if you do `a->v()`, you are accessing the
pointer `a`. Oh, the compiler may not dereference that memory location just
to call the function (unless it's virtual). But this isn't about what
compilers do; it's about what the standard *says*. And `a->v()` is no less
of an access to the pointer `a` than `a->d = 4;` is.

And if you access an invalid pointer, you cause undefined behavior.

--
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/baad4d80-954b-4c34-8771-0283cf2e37fc%40isocpp.org.

------=_Part_601_1437900788.1468419622508
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Wednesday, July 13, 2016 at 7:03:42 AM UTC-4, Bengt Gus=
tafsson wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-l=
eft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"=
>It seems to me that by requiring that the type of the variable being decla=
red <i>stateless</i> really is empty you prevent your new feature from bein=
g used in maybe the most common use case exemplified by the container <i>Al=
loc </i>type. What&#39;s needed there is a potentially zero-sized member in=
 case the Alloc class is stateless, but which takes up as much space as nee=
ded if it is not.</div></blockquote><div><br>I called that specific case ou=
t as an example:<br><br><div class=3D"prettyprint" style=3D"background-colo=
r: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-style: soli=
d; border-width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><=
div class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-b=
y-prettify">template</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">&lt;</span><span style=3D"color: #008;" class=3D"styled-by-pretti=
fy">typename</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> </span><span style=3D"color: #606;" class=3D"styled-by-prettify">Alloc</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">&gt;</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span s=
tyle=3D"color: #008;" class=3D"styled-by-prettify">struct</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #606;" class=3D"styled-by-prettify">DataBlock</span><span style=3D"color:=
 #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 stateless</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify">is_empty_v</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">&lt;</span><span style=3D"color: #606;" cla=
ss=3D"styled-by-prettify">Alloc</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">&gt;)</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> </span><span style=3D"color: #606;" class=3D"styled-by-pre=
ttify">Alloc</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> a</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">};</span></div></code=
></div><br>`a` will take up no space if `Alloc` is empty. Also, you could u=
se `stateless(auto)` instead of the explicit `is_empty_v` test.<br><br>This=
 allows you to make a distinction between &quot;Make this object stateless =
where possible&quot; and &quot;If this type is not empty, then that&#39;s a=
n error.&quot; While the former is useful, the latter is also quite useful.=
 After all, if your type needs to be empty, and you&#39;re including a bunc=
h of other member types, you want to make sure nobody breaks your type&#39;=
s rules by accidentally adding an NSDM or something.<br><br>That is:<br><di=
v class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); bord=
er-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; word-=
wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint=
"><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><spa=
n style=3D"color: #008;" class=3D"styled-by-prettify">struct</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"co=
lor: #606;" class=3D"styled-by-prettify">OtherType</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br>=C2=A0 stateless </span><span style=3D"color: =
#606;" class=3D"styled-by-prettify">First</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"> f</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br>=C2=A0 </span><span style=3D"color: #606;" class=3D"styl=
ed-by-prettify">Second</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> s</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </sp=
an><span style=3D"color: #800;" class=3D"styled-by-prettify">//Oops, forgot=
 to declare that stateless.</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"><br></span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">};</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"><br><br></span><span style=3D"color: #008;" class=3D"styled-by-prettify"=
>struct</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </=
span><span style=3D"color: #606;" class=3D"styled-by-prettify">MyType</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 stateless </span><sp=
an style=3D"color: #606;" class=3D"styled-by-prettify">OtherType</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> o</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">};</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br></span></div></code></div><br>`MyType` should b=
e <i>guaranteed</i> to be empty, just as if you had declared no members at =
all. If `OtherType` doesn&#39;t play along, then there clearly ought to be =
a compile error.<br><br></div><blockquote class=3D"gmail_quote" style=3D"ma=
rgin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">=
<div dir=3D"ltr"><div></div><div>I commend you for pointing out that even c=
lasses with virtual methods can be empty, but maybe your paper should elabo=
rate a little on why: You think of such an object as containing only a vtbl=
 pointer but as it is a by-value member of its containing object you don&#3=
9;t need the vtbl pointer as you know what it points to for each method any=
way.</div></div></blockquote><div><br>The Motivation and Scope section didn=
&#39;t exclude virtual types, but that was because they are <i>logically</i=
> empty. The Design section made it perfectly clear that types with virtual=
 functions or members are not considered empty and thus are not eligible to=
 be used statelessly.<br><br></div><blockquote class=3D"gmail_quote" style=
=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: =
1ex;"><div dir=3D"ltr"><div></div><div>Your idea of allowing a class declar=
ation to be declared stateless is scary as it removes the declaration of th=
e statelessness from the usage. Now you can declare a std::vector&lt;T&gt; =
with a stateless T and, well, it is hard to tell if this would work. If siz=
eof(T) is 1 for a stateless T it could but would waste heap memory.</div></=
div></blockquote><div><br>Looking back at the proposal, I don&#39;t think I=
 made my intentions with stateless types sufficiently explicit.<br><br>With=
 two exceptions that I&#39;ll get to in a moment, a stateless type can be u=
sed exactly like any other type. You can heap allocate them, use placement =
new, etc. When you use a stateless type to directly create an object in a w=
ay that cannot have `stateless` applied (stack variables, `new`, etc), then=
 the object behaves just like any empty type. So if you use `std::allocate&=
lt;Stateless&gt;::allocate(5)`, you will get an array of 5 empty objects. A=
 vector of stateless types is no different from a vector of empty types.<br=
><br>However, if you use a stateless type to declare an object for which `s=
tateless` <i>can</i> be applied (direct NSDM or base class of a non-union c=
lass type), then `stateless` is implicitly added to that declaration. So a =
stateless type declaration is simply saying that the objects created from i=
t will be stateless wherever possible. And that is only possible as a direc=
t subobject of a non-union class type.<br><br>Remember: the goal of this pr=
oposal is <i>not</i> to allow zero-sized objects (and arrays). The goal is =
to make empty subobjects be able to not affect the layout of the type. A `v=
ector&lt;T&gt;` does not create its Ts as subobjects of a type. So the fact=
 that `T` is a stateless type is irrelevant.<br><br>When it comes to statel=
ess types, there are really only two choices for what should happen if you =
use them in a non-stateless way. Either it is an explicit error, or it is l=
egal and behaves as it normally would (ie: like any empty type).<br><br>My =
proposal suggests the latter. Earlier versions preferred the former, but th=
at plays extreme havoc with using stateless types in template code. The mos=
t obvious example being `tuple`; if you give it a stateless type, it should=
 still be able to work. But if you use option 1, there is no way it possibl=
y could, since `tuple` implementations often rely on placement new and so f=
orth. And stateless types would be forbidden from being used by placement n=
ew. Oh sure, with option 2 there&#39;s no guarantee that a tuple implementa=
tion will actually make the contained value <i>stateless</i>. But at least =
the code would compile and function adequately.<br><br>My proposal makes tw=
o exceptions for option 2: stateless types as NSDM arrays, and stateless ty=
pes in unions. You could allow stateless types to be in unions and NSDM arr=
ays.
 However, their behavior would <i>not</i> be stateless.<br><br>The reason t=
o forbid them is mainly=20
sanity. A user who doesn&#39;t understand the complexities of C++ may well =
expect an NSDM array of stateless types to be a=20
stateless array. But it won&#39;t; it&#39;ll just be an array of empty clas=
ses, and the size of the containing type would be adjusted appropriately. B=
y contrast, if you declare a stack variable of a stateless type, the user h=
as no easy (standard-provided) way to tell if this actually takes up room o=
n the stack. Whereas `sizeof` is very much standard-provided.<br><br>I&#39;=
m=20
open to being convinced otherwise however. Particularly with template code.=
<br>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin=
-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"lt=
r"><div>As long as the stateless property is on the variable the code acces=
sing the variable can work with the restrictions that this qualifier introd=
uces.</div></div></blockquote><div></div><blockquote class=3D"gmail_quote" =
style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-l=
eft: 1ex;"><div dir=3D"ltr"><div></div><div>I don&#39;t see the problem wit=
h array iteration that you state &quot;<span style=3D"color:rgb(0,0,0);font=
-family:&quot;Times New Roman&quot;;font-size:medium">=C2=A0If the stateles=
s array has a count larger than 1, and it is contained in an empty class, t=
here is no guarantee that adding a number larger than 1 will result in a va=
lid address for the purposes of iteration.&quot;</span></div><div>The addre=
ss is going to be just as valid as for any iteration. Yes, the address can =
point to memory that would cause an access violation if accessed, but there=
 is no state to access there anyway, so doing so deserves an access violati=
on. What could possibly happen is that if you declare a very large array of=
 zero sized objects the address could wrap around causing loops with &lt; e=
nd conditions to stop immediately. Is this what you mean? I would say that =
this case is arcane enough to let through with a recommendation: Don&#39;t =
use &lt; tests on loop pointers when iterating over stateless objects. (Her=
e again is a difference between a stateless variable and a stateless class:=
 if stateless claesses are allowed this has to be extended to: Don&#39;t us=
e &lt; tests in loops in template code). In any case, as you mention: The t=
his pointer for any method call inside the loop body would not care if the =
address was actually outside the memory area (0 bytes) allocated for the ar=
ray... it will not use the this pointer anyway.</div></div></blockquote><di=
v><br>As far as C++ is concerned, if you do `a-&gt;v()`, you are accessing =
the pointer `a`. Oh, the compiler may not dereference that memory location =
just to call the function (unless it&#39;s virtual). But this isn&#39;t abo=
ut what compilers do; it&#39;s about what the standard <i>says</i>. And `a-=
&gt;v()` is no less of an access to the pointer `a` than `a-&gt;d =3D 4;` i=
s.<br><br>And if you access an invalid pointer, you cause undefined behavio=
r.</div></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/baad4d80-954b-4c34-8771-0283cf2e37fc%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/baad4d80-954b-4c34-8771-0283cf2e37fc=
%40isocpp.org</a>.<br />

------=_Part_601_1437900788.1468419622508--

------=_Part_600_1606007593.1468419622508--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Wed, 13 Jul 2016 11:18:31 -0700 (PDT)
Raw View
------=_Part_811_1519885034.1468433911353
Content-Type: multipart/alternative;
 boundary="----=_Part_812_883563444.1468433911353"

------=_Part_812_883563444.1468433911353
Content-Type: text/plain; charset=UTF-8

Here's a small update to the idea, after receiving commentary. It explains
the behavior of stateless types hopefully more explicitly. It also adds a
notation that stateless subobjects still impose their alignments on their
containing types. So if you declare that an empty class has 8 byte
alignment, then classes which statelessly use it will have at least 8 byte
alignment. Even though it doesn't take up size.

Also, I've been thinking about complexity reduction (this isn't reflected
in the new version). I'm starting to think that `stateless` doesn't need
full constant-expression conditionals.

At subobject declarations, there are 3 scenarios of interest: 1) The user
requires the subobject to be stateless and therefore the type must be
empty. 2) The user wants the subobject to be stateless if the type allows
that, but if not then it won't be stateless. 3) The user doesn't care.

With type declarations, there are 3 scenarios of interest: 1) The user
wants all potentially stateless uses of the type to be stateless, so fail
if the type is non-empty. 2) The user wants all potentially stateless uses
of the type to be stateless *if* the type is empty, but otherwise be
non-stateless. 3) The user does not want all potentially stateless uses of
the type to be stateless.

Even something like `std::pair` doesn't need a conditional. A
`pair<stateless1, stateless2>` is an empty type, and therefore we could
declare that `pair` would be stateless if both types passed to it are
stateless.

--
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/3ffd6df6-ba77-414c-aeef-7ec23206bb88%40isocpp.org.

------=_Part_812_883563444.1468433911353
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Here&#39;s a small update to the idea, after receiving com=
mentary. It explains the behavior of stateless types hopefully more explici=
tly. It also adds a notation that stateless subobjects still impose their a=
lignments on their containing types. So if you declare that an empty class =
has 8 byte alignment, then classes which statelessly use it will have at le=
ast 8 byte alignment. Even though it doesn&#39;t take up size.<br><br>Also,=
 I&#39;ve been thinking about complexity reduction (this isn&#39;t reflecte=
d in the new version). I&#39;m starting to think that `stateless` doesn&#39=
;t need full constant-expression conditionals.<br><br>At subobject declarat=
ions, there are 3 scenarios of interest: 1) The user requires the subobject=
 to be stateless and therefore the type must be empty. 2) The user wants th=
e subobject to be stateless if the type allows that, but if not then it won=
&#39;t be stateless. 3) The user doesn&#39;t care.<br><br>With type declara=
tions, there are 3 scenarios of interest: 1) The user wants all potentially=
 stateless uses of the type to be stateless, so fail if the type is non-emp=
ty. 2) The user wants all potentially stateless uses of the type to be stat=
eless <i>if</i> the type is empty, but otherwise be non-stateless. 3) The u=
ser does not want all potentially stateless uses of the type to be stateles=
s.<br><br>Even something like `std::pair` doesn&#39;t need a conditional. A=
 `pair&lt;stateless1, stateless2&gt;` is an empty type, and therefore we co=
uld declare that `pair` would be stateless if both types passed to it are s=
tateless.<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/3ffd6df6-ba77-414c-aeef-7ec23206bb88%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/3ffd6df6-ba77-414c-aeef-7ec23206bb88=
%40isocpp.org</a>.<br />

------=_Part_812_883563444.1468433911353--

------=_Part_811_1519885034.1468433911353
Content-Type: text/html; charset=UTF-8; name="Stateless Subobjects.html"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename="Stateless Subobjects.html"
X-Attachment-Id: 948b4e3c-353c-4f12-b2b4-3e75484bea3a
Content-ID: <948b4e3c-353c-4f12-b2b4-3e75484bea3a>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.=
w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns=3D"http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8" =
/>
  <meta http-equiv=3D"Content-Style-Type" content=3D"text/css" />
  <meta name=3D"generator" content=3D"pandoc" />
  <meta name=3D"date" content=3D"2016-07-13" />
  <title>Stateless Subobjects and Types, pre-release v2.</title>
  <style type=3D"text/css">code{white-space: pre;}</style>
</head>
<body>
<div id=3D"header">
<h1 class=3D"title">Stateless Subobjects and Types, pre-release v2.</h1>
<h3 class=3D"date">July 13, 2016</h3>
</div>
<div id=3D"TOC">
<ul>
<li><a href=3D"#motivation-and-scope">Motivation and Scope</a></li>
<li><a href=3D"#design">Design</a><ul>
<li><a href=3D"#implementation-and-restrictions">Implementation and Restric=
tions</a></li>
</ul></li>
<li><a href=3D"#potential-issues">Potential issues</a><ul>
<li><a href=3D"#the-unknown">The Unknown</a></li>
</ul></li>
<li><a href=3D"#alternative-designs-explored">Alternative Designs Explored<=
/a><ul>
<li><a href=3D"#magic-standard-library-wrapper-type">Magic standard library=
 wrapper type</a></li>
</ul></li>
<li><a href=3D"#changelist">Changelist</a><ul>
<li><a href=3D"#from-pre-release-v1">From pre-release v1:</a></li>
</ul></li>
<li><a href=3D"#acknowledgments">Acknowledgments</a></li>
</ul>
</div>
<p>This proposal specifies the ability to declare member and base class sub=
objects which do not take up space in the objects they are contained within=
.. It also allows the user to define classes which will always be used in su=
ch a fashion.</p>
<h1 id=3D"motivation-and-scope">Motivation and Scope</h1>
<p>An object is stateless, conceptually speaking, if it has no non-static d=
ata members. As such, the state of any particular instance is no different =
from another. Because of this, there is no conceptual reason why a stateles=
s object needs to have a region of storage associated with it.</p>
<p>In C++, a class would be stateless if it has no non-static data members =
(NSDMs) and all of its base classes likewise are stateless as well. <code>i=
s_empty_v</code> qualifies as a useful test, but technically other classes =
could qualify as well (those with virtual members/base classes).</p>
<p>There are many times when a user wants to use a class that the user prov=
ides, but the class may or may not be logically stateless. If it is statele=
ss, then it would be best if the class which uses it would not grow in size=
 simply due to the presence of the stateless subobject. After all, a concep=
tually stateless object does not need to take up space to do its job.</p>
<p>To avoid this, users will frequently use standard layout rules and the e=
mpty base optimization to allow them to have access to a stateless subobjec=
t:</p>
<pre><code>template&lt;typename Alloc&gt;
struct DataBlock : public Alloc
{
};</code></pre>
<p>In this case, if <code>Alloc</code> is empty, then so long as <code>Data=
Block</code> follows standard layout rules, the user is guaranteed that <co=
de>DataBlock</code> is no larger than it would have been if <code>Alloc</co=
de> were not empty. Even if it does not follow standard layout, the compile=
r is free to optimize the empty base <code>Alloc</code> away.</p>
<p>There are of course problems with such a use. If <code>Alloc</code> is n=
ot empty (and <code>DataBlock</code> does not require that it is), and <cod=
e>Alloc</code> declares a virtual function, it is possible that <code>DataB=
lock&lt;Alloc&gt;</code> will accidentally override that virtual function. =
Or not quite override it and cause a compile error. Whereas if <code>Alloc<=
/code> were a non-static data member, this could easily be avoided.</p>
<p>Equally importantly, this use of <code>Alloc</code> is simply not how a =
user would naturally write this class. Inheritance is supposed to model an =
&quot;is a&quot; relationship. Yet conceptually, <code>DataBlock</code> is =
not an <code>Alloc</code>; it <em>has</em> an <code>Alloc</code>. <code>Dat=
aBlock</code> uses inheritance, not to model a relationship, but as an opti=
mization tool, to keep the class from growing unnecessarily.</p>
<p>The intent of this proposal is to permit, among other things, classes li=
ke <code>DataBlock</code> to declare <code>Alloc</code> as a non-static dat=
a member. And if <code>Alloc</code> is empty, then <code>DataBlock</code> c=
an use syntax to make the <code>Alloc</code> NSDM take up no space in <code=
>DataBlock</code>'s layout.</p>
<p>This would also be recursive, so that if <code>Alloc</code> had no NSDMs=
, and <code>DataBlock&lt;Alloc&gt;</code> had no NSDMs besides the <code>Al=
loc</code> member, then <code>DataBlock&lt;Alloc&gt;</code> would also be c=
onsidered an empty type. And therefore, some other type could use it in a s=
tateless fashion.</p>
<h1 id=3D"design">Design</h1>
<p>We define two concepts: stateless subobjects and stateless classes. A st=
ateless class is really just shorthand for the former; it declares that ins=
tances of the class can only be created as stateless subobjects of some oth=
er type.</p>
<p>Note: The following syntax is entirely preliminary. This proposal is not=
 wedded to the idea of introducing a new keyword or somesuch. This syntax i=
s here simply for the sake of understanding how the functionality should ge=
nerally be specified. The eventual syntax could be a contextual keyword lik=
e <code>final</code> and <code>override</code>, or it could be something el=
se.</p>
<h3 id=3D"stateless-subobojects">Stateless subobojects</h3>
<p>A non-static data member subobject of a type can be declared stateless w=
ith the following syntax:</p>
<pre><code>struct Data
{
    stateless Type val;
};</code></pre>
<p>A base class subobject of a type can be declared stateless with the foll=
owing syntax:</p>
<pre><code>struct Data : public stateless Type
{
    ...
};</code></pre>
<p>In both cases, if <code>Type</code> is not an empty class, then this is =
a compile error. <code>stateless</code> cannot be applied to a base class w=
hich uses <code>virtual</code> inheritance.</p>
<p>Member subobjects that are arrayed cannot be declared with <code>statele=
ss</code> property. Variables which are not non-static data members cannot =
be declared with the stateless property.</p>
<p><code>stateless</code> cannot be applied to a member of a <code>union</c=
ode> class.</p>
<p>The stateless property can be conditional, based on a compile-time condi=
tion like <code>noexcept</code>. This is done as follows:</p>
<pre><code>template&lt;typename Alloc&gt;
struct DataBlock
{
    stateless(is_empty_v&lt;Alloc&gt;) Alloc a;
};</code></pre>
<p>In this case, <code>a</code> will be a stateless member only if its type=
 is empty. If the condition is false, then it is as if the stateless proper=
ty were not applied to the subobject.</p>
<p>To facilitate common use patterns, the <code>stateless(auto)</code> synt=
ax for subobjects shall be equivalent to <code>stateless(std::is_empty_v&lt=
;T&gt;)</code>, where <code>T</code> is the type of the subobject being dec=
lared.</p>
<h3 id=3D"stateless-behavior">Stateless behavior</h3>
<p>Stateless subobjects have no effect on the layout or size of their conta=
ining object. Similarly, the rules for standard layout types ignore the pre=
sence of any stateless subobjects. And thus, two classes can be layout comp=
atible even if they differ by the presence of stateless subobjects.</p>
<p>Stateless subobjects otherwise have the same effects on their containing=
 types as regular subobjects do. For example, a stateless subobject can cau=
se its container to not be trivially copyable, if it has a non-trivial copy=
 constructor (even though the object by definition has no state to copy).</=
p>
<p>The definition of &quot;empty class&quot; (per <code>std::is_empty</code=
>) must now be expanded. The rules for an empty class are:</p>
<ul>
<li>Non-union class.</li>
<li>No virtual functions.</li>
<li>No virtual base classes.</li>
<li>No non-empty base classes.</li>
<li>No non-stateless NSDMs.</li>
</ul>
<p>In all other ways, except where detailed below, a stateless subobject wo=
rks identically to a non-stateless one. Stateless subobjects are initialize=
d and destroyed just as if they were not stateless. Stateless subobjects un=
dergo copy and move construction and assignment along with all other subobj=
ects (though they will likely not be doing much). In particular, stateless =
subobjects are still members/base classes of the types that contain them, s=
o aggregate initialization of members (and bases) will still have to take t=
hem into account:</p>
<pre><code>struct foo {};

struct aggregate
{
  stateless foo f;
  int b;
};

//It may have no state, but `f` must still be initialized.
aggregate agg =3D {{}, 4};</code></pre>
<p>Note that the alignment of a stateless subobject will still impact the a=
lignment of the containing class. A <code>stateless</code> member declarati=
on can include an <code>alignas</code> specifier as well.</p>
<h3 id=3D"stateless-types">Stateless types</h3>
<p>The stateless property can be applied to (non-union) types as well:</p>
<pre><code>stateless class ClassName : BaseClasses
{
    ...
};</code></pre>
<p>The <code>stateless</code> keyword must be consistently associated with =
any forward declarations for stateless types.</p>
<pre><code>class ClassName;  //Not a stateless type.

stateless class ClassName  //Compiler error: you told me it wasn&#39;t stat=
eless before.
{
};</code></pre>
<p>And vice-versa.</p>
<p>A stateless class definition is ill-formed if the class is not empty (pe=
r the expanded rules for empty classes).</p>
<p>The size of a stateless class is not modified by being stateless. Theref=
ore, the size of a stateless class shall be no different from the size of a=
ny other empty class.</p>
<p>The statelessness of a type can be conditional, just like subobjects:</p=
>
<pre><code>template&lt;typename T&gt;
stateless(is_empty_v&lt;T&gt;) struct Foo : public T {};</code></pre>
<p>Here, <code>Foo</code> may or may not be stateless, depending on whether=
 <code>T</code> is empty. If the constant expression evaluates to <code>fal=
se</code>, then the class is not stateless.</p>
<p>To make certain conditions easier, there will be the <code>stateless(aut=
o)</code> syntax. When applied to a class declaration, <code>stateless(auto=
)</code> will cause the class to be stateless if the class is empty. If the=
 class is not empty, then the class will not be stateless.</p>
<p>When a stateless class is used to create an object in a way that cannot =
have <code>stateless</code> applied to it, then the code behaves just as it=
 would if the class did not have the <code>stateless</code> keyword. Theref=
ore, you can heap allocate arrays of stateless classes, and they will funct=
ion just like any heap allocated array of empty classes. You can declare an=
 automatic variable of a stateless type, and it will behave as any empty cl=
ass (note: implementations may optimize such objects to take up no stack sp=
ace if possible, but they are not required to do so).</p>
<p>However, when a stateless class is used to declare a direct subobject of=
 another type, that subobject will be implicitly stateless. It is perfectly=
 valid to explicitly specify <code>stateless</code> on a member/base class =
of a stateless type as well. If the conditions on the two <code>stateless</=
code> properties do not agree (one resolves to true and the other false), t=
hen the program is il-formed.<a href=3D"#fn1" class=3D"footnoteRef" id=3D"f=
nref1"><sup>1</sup></a></p>
<p>Declaring an array of a stateless type as an NSDM is forbidden. Stateles=
s types may not be used as members of a union.</p>
<p>The standard library does not need to have a traits class to detect if a=
 type is stateless. A type with such a declaration can be used in any way t=
hat any type can, so <code>is_empty</code> is sufficient.</p>
<h3 id=3D"stateless-anonymous-types">Stateless anonymous types</h3>
<p>Statelessness can be applied to anonymous types as well:</p>
<pre><code>stateless(auto) struct
{
    Data d;
} varName;</code></pre>
<p>The <code>stateless</code> property applies to the struct declaration, n=
ot the variable. As such, <code>decltype(varName)</code> will be a stateles=
s type if <code>Data</code> is a stateless type. Such declarations can only=
 be made as non-static data members.</p>
<h2 id=3D"implementation-and-restrictions">Implementation and Restrictions<=
/h2>
<p>In a perfect world, the above would be the only restrictions on stateles=
s types. C++ of course is never perfect.</p>
<h3 id=3D"memory-locations">Memory locations</h3>
<p>In C++ as it currently stands, every object needs to have a memory locat=
ion. And two separate objects of unrelated types cannot have the <em>same</=
em> memory location.</p>
<p>Stateless subobojects effectively have to be able to break this rule. Th=
e memory location of a stateless subobject is more or less irrelevant. Sinc=
e the type is stateless, there is no independent state to access. So one in=
stance is functionally no different from another.<a href=3D"#fn2" class=3D"=
footnoteRef" id=3D"fnref2"><sup>2</sup></a></p>
<p>As such, the general idea is that a stateless subobject could have any a=
ddress within the storage of the object which contains it. This means that =
a stateless subobject can have the same address as any other subobject in i=
ts containing object's type.</p>
<p>This is not really an implementation problem, since stateless suboboject=
s by their very nature have no state to access. As such, the specific addre=
ss of their <code>this</code> pointer is irrelevant. What we need, standard=
-wise, is to modify the rules for accessing objects and aliasing to allow a=
 stateless subobject to have the same address as <em>any</em> other object.=
 Because stateless objects have no value to access, we may not even need to=
 change [basic.lval]/10.</p>
<p>The address of a stateless subobject can be any address within the stora=
ge of the object that contains it. The standard need not specify exactly wh=
ich address.</p>
<p>Implementation-wise, the difficulty will be in changing how types are la=
id out. That is, modifying ABIs to allow member subobjects that have no siz=
e and enforcing EBO even when it might otherwise have been forbidden.</p>
<p>The behavior of the <em>user</em> converting pointers/references between=
 two unrelated stateless subobjects should still be undefined. We just need=
 rules to allow stateless subobjects to be assigned a memory location at th=
e discretion of the compiler, which may not be unique from other unrelated =
objects.</p>
<h3 id=3D"stateless-arrays">Stateless arrays</h3>
<p>This design expressly forbids the declaration of stateless member subobj=
ects that are arrayed. The reason for this has to do with pointer arithmeti=
c.</p>
<p>In C++, the following should be perfectly valid for any type <code>T</co=
de>, regarldess of where the array of <code>T</code> is declared:</p>
<pre><code>T t[5];
T *first =3D &amp;t[0];
T *last =3D first + 5;
assert(sizeof(T) * 5 =3D=3D last - first);</code></pre>
<p>The whole point of a stateless subobject is that it does not take up spa=
ce within another type. If the array above were a member of another type, t=
his code still ought to work. But, since <code>sizeof(T)</code> is non-zero=
, that means that those values have to take up space somewhere. Each pointe=
r has to be valid.</p>
<p>Under non-array conditions, the pointer to a stateless subobject could a=
lways have the same address as its container (recursively, to the last non-=
stateless container). Adding 1 to any such pointer will still be a valid ad=
dress; this is required because any object can be considered an array of 1 =
value ([expr.add]/4). If the containing class is an empty class with a size=
 of 1, then adding one to a stateless member's pointer is no less valid tha=
n adding 1 to the container's address.</p>
<p>When dealing with an array, this is not necessarily the case. If the sta=
teless array has a count larger than 1, and it is contained in an empty cla=
ss, there is no guarantee that adding a number larger than 1 will result in=
 a valid address for the purposes of iteration.</p>
<p>Several alternatives were considered:</p>
<ol style=3D"list-style-type: decimal">
<li><p>Declare that <code>sizeof</code> for stateless subobjects is zero. I=
 am not nearly familiar enough with the C++ standard to know the level of h=
orrors that this would unleash, but I can imagine that it's very bad. It wo=
uld also make it impossible to have a distinction between stateless subobje=
cts and stateless types, as the <code>sizeof</code> can be applied to a poi=
nter to the object, which cannot know if the object it points to is statele=
ss.</p></li>
<li><p>Declare that stateless subobjects which are arrayed will still take =
up space as though they were not declared <code>stateless</code>.</p></li>
<li><p>Forbid declaring arrays of stateless subobjects altogether.</p></li>
</ol>
<p>Option 1 is probably out due to various potential issues. #2 seems tempt=
ing, but it makes the use of <code>stateless T arr[4];</code> something of =
a lie. Earlier designs used #3, then switched to #2. But the current design=
 goes back to #3 for an important reason.</p>
<p>In the current design, it is the <em>use</em> of a type which is statele=
ss. Types can be declared stateless as well, but this really only means tha=
t all uses of them to declare objects will implicitly be stateless. So this=
 restricts how the type may be used, but not the semantics of it.</p>
<p>Because statelessness can be applied to any empty class at its point of =
use, if a user wants to be able to use an empty class in a non-stateless wa=
y, then they simply do not declare the class to be stateless.</p>
<p>And therefore, if you declare a class to be stateless, you truly intend =
for it to only be used as a subobject of another type. This would be useful=
 for a CRTP base class, for example, where it is a logical error to create =
an object of the class which is not a base class.</p>
<h3 id=3D"trivial-copyability">Trivial copyability</h3>
<p>Trivial copyability is another area that can be problematic with statele=
ss subobjects. We explicitly forbid trivial copying into a base class subob=
ject of another class ([basic.types]/2).</p>
<p>Similarly, we must explicitly forbid trivial copying into stateless subo=
bojects. Trivial copying <em>from</em> a stateless subobject should be OK. =
Though this is only &quot;OK&quot; in the sense that the program is not ill=
-formed or that there us undefined behavior. The value copied is undefined,=
 but that doesn't matter, since you could only ever use that value to initi=
alize a type that is layout compatible with an empty class. Namely, another=
 empty class. And empty classes have no value.</p>
<h3 id=3D"offsetof">offsetof</h3>
<p><code>offsetof</code> will obviously not be affected by stateless subobj=
ect members of another type. However, if <code>offsetof</code> is applied t=
o a stateless subobject, what is the result?</p>
<p>I would suggest that this either be undefined or 0.</p>
<h1 id=3D"potential-issues">Potential issues</h1>
<h2 id=3D"the-unknown">The Unknown</h2>
<p>One of the most difficult aspects of dealing with any form of stateless =
type system is that it represents something that is very new and very compl=
icated for C++ to deal with. As such, the wording for this needs to be quit=
e precise and comprehensive, lest we introduce subtle bugs into the standar=
d.</p>
<p>A good spec doctor needs to be involved with the standardization of this=
 feature.</p>
<h1 id=3D"alternative-designs-explored">Alternative Designs Explored</h1>
<p>There has been many alternatives towards achieving the same ends. Every =
such alternative has to deal with 2 fundamental rules of the C++ object mod=
el:</p>
<ol style=3D"list-style-type: decimal">
<li>Objects are defined by a region of storage.</li>
<li>Two different object instances have different regions of storage.</li>
</ol>
<p>This current proposal is designed to avoid changes to rule #1. Stateless=
 subobjects in this proposal still have a non-zero size. Instead, changes t=
o rule #2 are made to permit such subobjects to be able to not disturb the =
layout of their container.</p>
<p>Other alternatives take a different approach to dealing with these rules=
..</p>
<h2 id=3D"magic-standard-library-wrapper-type">Magic standard library wrapp=
er type</h2>
<p><a href=3D"https://groups.google.com/a/isocpp.org/d/msg/std-proposals/sA=
dqngl8pew/xCjHCLpuAAAJ">This idea</a> is focused on just the specific case =
of having empty classes potentially take up no space in their containing cl=
asses.</p>
<p>It would essentially declare a standard library type that is, in the con=
text of this proposal, something like this:</p>
<pre><code>template&lt;typename T&gt;
stateless(auto) struct allow_zero_size : public T {...};</code></pre>
<p>It is a wrapper which, when used as an NSDM, will not take up any space =
in its containing object if the given type is empty. And if it is not, then=
 it will.</p>
<p>The theoretical idea behind this is that it doesn't require new syntax. =
And in that proposal, <code>allow_zero_size</code> would not be forbidden f=
rom being in arrays or any of the other forbearances that this proposal for=
bids stateless types from.</p>
<p>This makes the behavior of such a type rather more difficult to specify.=
 The standard would still need to have changes to allow subobojects which t=
ake up no space to work, since users have to be able to get pointers/refere=
nces to them and the like. Once that work is done, exactly how you specify =
that a subobject takes up no space does not really matter.</p>
<h1 id=3D"changelist">Changelist</h1>
<h2 id=3D"from-pre-release-v1">From pre-release v1:</h2>
<ul>
<li><p>Clarified that stateless types act like regular empty types in all c=
ases except when declared as direct subobjects of classes.</p></li>
<li><p>Explicitly noted that the alignment of stateless subobjects will be =
respected by their containers.</p></li>
</ul>
<h1 id=3D"acknowledgments">Acknowledgments</h1>
<p>From the C++ Future Discussions forum:</p>
<ul>
<li>Avi Kivity</li>
<li>A. Jo=C3=ABl Lamotte, who's original thread on <a href=3D"https://group=
s.google.com/a/isocpp.org/d/msg/std-proposals/u35GIuJECcQ/Yorc58iiBwAJ">Inl=
ine Classes</a> was the seed for this idea.</li>
<li>Vicente J. Botet Escriba</li>
<li>Matt Calabrese</li>
<li>Andrew Tomazos</li>
<li>Matthew Woehlke</li>
<li>Bengt Gustafsson</li>
</ul>
<div class=3D"footnotes">
<hr />
<ol>
<li id=3D"fn1"><p>It may be reasonable to use the logical <code>or</code> b=
etween the two, instead of failing on a mis-match.<a href=3D"#fnref1">=E2=
=86=A9</a></p></li>
<li id=3D"fn2"><p>Yes, it is be possible for an otherwise empty type to use=
 its own <code>this</code> pointer as its state. This could be used to regi=
ster itself with some global system or perform some other side-effect. The =
current rules ensure, even with EBO, that an empty object instance will alw=
ays have a distinct <code>this</code> pointer from any other instance of th=
at type. However, such types would be inappropriate to use as stateless typ=
es, since they are not logically stateless. Further, I find it highly unlik=
ely that such code is sufficiently widespread to be much of a problem. It w=
ould be better for makers of such classes to simply declare an unused membe=
r of type <code>char</code>, to prevent themselves from being considered em=
pty.<a href=3D"#fnref2">=E2=86=A9</a></p></li>
</ol>
</div>
</body>
</html>

------=_Part_811_1519885034.1468433911353
Content-Type: text/x-markdown; charset=UTF-8; name="Stateless Subobjects.md"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename="Stateless Subobjects.md"
X-Attachment-Id: 7697fdc3-8b60-46e4-8432-8fbab5d13fe1
Content-ID: <7697fdc3-8b60-46e4-8432-8fbab5d13fe1>

% Stateless Subobjects and Types, pre-release v2
%
% July 13, 2016

This proposal specifies the ability to declare member and base class subobj=
ects which do not take up space in the objects they are contained within. I=
t also allows the user to define classes which will always be used in such =
a fashion.

# Motivation and Scope

An object is stateless, conceptually speaking, if it has no non-static data=
 members. As such, the state of any particular instance is no different fro=
m another. Because of this, there is no conceptual reason why a stateless o=
bject needs to have a region of storage associated with it.

In C++, a class would be stateless if it has no non-static data members (NS=
DMs) and all of its base classes likewise are stateless as well. `is_empty_=
v` qualifies as a useful test, but technically other classes could qualify =
as well (those with virtual members/base classes).

There are many times when a user wants to use a class that the user provide=
s, but the class may or may not be logically stateless. If it is stateless,=
 then it would be best if the class which uses it would not grow in size si=
mply due to the presence of the stateless subobject. After all, a conceptua=
lly stateless object does not need to take up space to do its job.

To avoid this, users will frequently use standard layout rules and the empt=
y base optimization to allow them to have access to a stateless subobject:

=09template<typename Alloc>
=09struct DataBlock : public Alloc
=09{
=09};

In this case, if `Alloc` is empty, then so long as `DataBlock` follows stan=
dard layout rules, the user is guaranteed that `DataBlock` is no larger tha=
n it would have been if `Alloc` were not empty. Even if it does not follow =
standard layout, the compiler is free to optimize the empty base `Alloc` aw=
ay.

There are of course problems with such a use. If `Alloc` is not empty (and =
`DataBlock` does not require that it is), and `Alloc` declares a virtual fu=
nction, it is possible that `DataBlock<Alloc>` will accidentally override t=
hat virtual function. Or not quite override it and cause a compile error. W=
hereas if `Alloc` were a non-static data member, this could easily be avoid=
ed.

Equally importantly, this use of `Alloc` is simply not how a user would nat=
urally write this class. Inheritance is supposed to model an "is a" relatio=
nship. Yet conceptually, `DataBlock` is not an `Alloc`; it *has* an `Alloc`=
.. `DataBlock` uses inheritance, not to model a relationship, but as an opti=
mization tool, to keep the class from growing unnecessarily.

The intent of this proposal is to permit, among other things, classes like =
`DataBlock` to declare `Alloc` as a non-static data member. And if `Alloc` =
is empty, then `DataBlock` can use syntax to make the `Alloc` NSDM take up =
no space in `DataBlock`'s layout.

This would also be recursive, so that if `Alloc` had no NSDMs, and `DataBlo=
ck<Alloc>` had no NSDMs besides the `Alloc` member, then `DataBlock<Alloc>`=
 would also be considered an empty type. And therefore, some other type cou=
ld use it in a stateless fashion.

# Design

We define two concepts: stateless subobjects and stateless classes. A state=
less class is really just shorthand for the former; it declares that instan=
ces of the class can only be created as stateless subobjects of some other =
type.

Note: The following syntax is entirely preliminary. This proposal is not we=
dded to the idea of introducing a new keyword or somesuch. This syntax is h=
ere simply for the sake of understanding how the functionality should gener=
ally be specified. The eventual syntax could be a contextual keyword like `=
final` and `override`, or it could be something else.

### Stateless subobojects

A non-static data member subobject of a type can be declared stateless with=
 the following syntax:

=09struct Data
=09{
=09=09stateless Type val;
=09};
=09
A base class subobject of a type can be declared stateless with the followi=
ng syntax:

=09struct Data : public stateless Type
=09{
=09=09...
=09};

In both cases, if `Type` is not an empty class, then this is a compile erro=
r. `stateless` cannot be applied to a base class which uses `virtual` inher=
itance.

Member subobjects that are arrayed cannot be declared with `stateless` prop=
erty. Variables which are not non-static data members cannot be declared wi=
th the stateless property.

`stateless` cannot be applied to a member of a `union` class.

The stateless property can be conditional, based on a compile-time conditio=
n like `noexcept`. This is done as follows:

=09template<typename Alloc>
=09struct DataBlock
=09{
=09=09stateless(is_empty_v<Alloc>) Alloc a;
=09};

In this case, `a` will be a stateless member only if its type is empty. If =
the condition is false, then it is as if the stateless property were not ap=
plied to the subobject.

To facilitate common use patterns, the `stateless(auto)` syntax for subobje=
cts shall be equivalent to `stateless(std::is_empty_v<T>)`, where `T` is th=
e type of the subobject being declared.

### Stateless behavior

Stateless subobjects have no effect on the layout or size of their containi=
ng object. Similarly, the rules for standard layout types ignore the presen=
ce of any stateless subobjects. And thus, two classes can be layout compati=
ble even if they differ by the presence of stateless subobjects.

Stateless subobjects otherwise have the same effects on their containing ty=
pes as regular subobjects do. For example, a stateless subobject can cause =
its container to not be trivially copyable, if it has a non-trivial copy co=
nstructor (even though the object by definition has no state to copy).

The definition of "empty class" (per `std::is_empty`) must now be expanded.=
 The rules for an empty class are:

* Non-union class.
* No virtual functions.
* No virtual base classes.
* No non-empty base classes.
* No non-stateless NSDMs.

In all other ways, except where detailed below, a stateless subobject works=
 identically to a non-stateless one. Stateless subobjects are initialized a=
nd destroyed just as if they were not stateless. Stateless subobjects under=
go copy and move construction and assignment along with all other subobject=
s (though they will likely not be doing much). In particular, stateless sub=
objects are still members/base classes of the types that contain them, so a=
ggregate initialization of members (and bases) will still have to take them=
 into account:

=09struct foo {};

=09struct aggregate
=09{
=09  stateless foo f;
=09  int b;
=09};

=09//It may have no state, but `f` must still be initialized.
=09aggregate agg =3D {{}, 4};

Note that the alignment of a stateless subobject will still impact the alig=
nment of the containing class. A `stateless` member declaration can include=
 an `alignas` specifier as well.

### Stateless types

The stateless property can be applied to (non-union) types as well:

=09stateless class ClassName : BaseClasses
=09{
=09=09...
=09};

The `stateless` keyword must be consistently associated with any forward de=
clarations for stateless types.

=09class ClassName;  //Not a stateless type.

=09stateless class ClassName  //Compiler error: you told me it wasn't state=
less before.
=09{
=09};

And vice-versa.

A stateless class definition is ill-formed if the class is not empty (per t=
he expanded rules for empty classes).

The size of a stateless class is not modified by being stateless. Therefore=
, the size of a stateless class shall be no different from the size of any =
other empty class.

The statelessness of a type can be conditional, just like subobjects:

=09template<typename T>
=09stateless(is_empty_v<T>) struct Foo : public T {};
=09
Here, `Foo` may or may not be stateless, depending on whether `T` is empty.=
 If the constant expression evaluates to `false`, then the class is not sta=
teless.

To make certain conditions easier, there will be the `stateless(auto)` synt=
ax. When applied to a class declaration, `stateless(auto)` will cause the c=
lass to be stateless if the class is empty. If the class is not empty, then=
 the class will not be stateless.

When a stateless class is used to create an object in a way that cannot hav=
e `stateless` applied to it, then the code behaves just as it would if the =
class did not have the `stateless` keyword. Therefore, you can heap allocat=
e arrays of stateless classes, and they will function just like any heap al=
located array of empty classes. You can declare an automatic variable of a =
stateless type, and it will behave as any empty class (note: implementation=
s may optimize such objects to take up no stack space if possible, but they=
 are not required to do so).

However, when a stateless class is used to declare a direct subobject of an=
other type, that subobject will be implicitly stateless. It is perfectly va=
lid to explicitly specify `stateless` on a member/base class of a stateless=
 type as well. If the conditions on the two `stateless` properties do not a=
gree (one resolves to true and the other false), then the program is il-for=
med.[^1]

Declaring an array of a stateless type as an NSDM is forbidden. Stateless t=
ypes may not be used as members of a union.

The standard library does not need to have a traits class to detect if a ty=
pe is stateless. A type with such a declaration can be used in any way that=
 any type can, so `is_empty` is sufficient.

### Stateless anonymous types

Statelessness can be applied to anonymous types as well:

=09stateless(auto) struct
=09{
=09=09Data d;
=09} varName;

The `stateless` property applies to the struct declaration, not the variabl=
e. As such, `decltype(varName)` will be a stateless type if `Data` is a sta=
teless type. Such declarations can only be made as non-static data members.

## Implementation and Restrictions

In a perfect world, the above would be the only restrictions on stateless t=
ypes. C++ of course is never perfect.

### Memory locations

In C++ as it currently stands, every object needs to have a memory location=
.. And two separate objects of unrelated types cannot have the *same* memory=
 location.

Stateless subobojects effectively have to be able to break this rule. The m=
emory location of a stateless subobject is more or less irrelevant. Since t=
he type is stateless, there is no independent state to access. So one insta=
nce is functionally no different from another.[^2]

As such, the general idea is that a stateless subobject could have any addr=
ess within the storage of the object which contains it. This means that a s=
tateless subobject can have the same address as any other subobject in its =
containing object's type.

This is not really an implementation problem, since stateless subobojects b=
y their very nature have no state to access. As such, the specific address =
of their `this` pointer is irrelevant. What we need, standard-wise, is to m=
odify the rules for accessing objects and aliasing to allow a stateless sub=
object to have the same address as *any* other object. Because stateless ob=
jects have no value to access, we may not even need to change [basic.lval]/=
10.

The address of a stateless subobject can be any address within the storage =
of the object that contains it. The standard need not specify exactly which=
 address.

Implementation-wise, the difficulty will be in changing how types are laid =
out. That is, modifying ABIs to allow member subobjects that have no size a=
nd enforcing EBO even when it might otherwise have been forbidden.

The behavior of the *user* converting pointers/references between two unrel=
ated stateless subobjects should still be undefined. We just need rules to =
allow stateless subobjects to be assigned a memory location at the discreti=
on of the compiler, which may not be unique from other unrelated objects.

### Stateless arrays

This design expressly forbids the declaration of stateless member subobject=
s that are arrayed. The reason for this has to do with pointer arithmetic.

In C++, the following should be perfectly valid for any type `T`, regarldes=
s of where the array of `T` is declared:

=09T t[5];
=09T *first =3D &t[0];
=09T *last =3D first + 5;
=09assert(sizeof(T) * 5 =3D=3D last - first);

The whole point of a stateless subobject is that it does not take up space =
within another type. If the array above were a member of another type, this=
 code still ought to work. But, since `sizeof(T)` is non-zero, that means t=
hat those values have to take up space somewhere. Each pointer has to be va=
lid.

Under non-array conditions, the pointer to a stateless subobject could alwa=
ys have the same address as its container (recursively, to the last non-sta=
teless container). Adding 1 to any such pointer will still be a valid addre=
ss; this is required because any object can be considered an array of 1 val=
ue ([expr.add]/4). If the containing class is an empty class with a size of=
 1, then adding one to a stateless member's pointer is no less valid than a=
dding 1 to the container's address.

When dealing with an array, this is not necessarily the case. If the statel=
ess array has a count larger than 1, and it is contained in an empty class,=
 there is no guarantee that adding a number larger than 1 will result in a =
valid address for the purposes of iteration.

Several alternatives were considered:

1. Declare that `sizeof` for stateless subobjects is zero. I am not nearly =
familiar enough with the C++ standard to know the level of horrors that thi=
s would unleash, but I can imagine that it's very bad. It would also make i=
t impossible to have a distinction between stateless subobjects and statele=
ss types, as the `sizeof` can be applied to a pointer to the object, which =
cannot know if the object it points to is stateless.

2. Declare that stateless subobjects which are arrayed will still take up s=
pace as though they were not declared `stateless`.

3. Forbid declaring arrays of stateless subobjects altogether.

Option 1 is probably out due to various potential issues. #2 seems tempting=
, but it makes the use of `stateless T arr[4];` something of a lie. Earlier=
 designs used #3, then switched to #2. But the current design goes back to =
#3 for an important reason.

In the current design, it is the *use* of a type which is stateless. Types =
can be declared stateless as well, but this really only means that all uses=
 of them to declare objects will implicitly be stateless. So this restricts=
 how the type may be used, but not the semantics of it.

Because statelessness can be applied to any empty class at its point of use=
, if a user wants to be able to use an empty class in a non-stateless way, =
then they simply do not declare the class to be stateless.

And therefore, if you declare a class to be stateless, you truly intend for=
 it to only be used as a subobject of another type. This would be useful fo=
r a CRTP base class, for example, where it is a logical error to create an =
object of the class which is not a base class.

### Trivial copyability

Trivial copyability is another area that can be problematic with stateless =
subobjects. We explicitly forbid trivial copying into a base class subobjec=
t of another class ([basic.types]/2).

Similarly, we must explicitly forbid trivial copying into stateless suboboj=
ects. Trivial copying *from* a stateless subobject should be OK. Though thi=
s is only "OK" in the sense that the program is not ill-formed or that ther=
e us undefined behavior. The value copied is undefined, but that doesn't ma=
tter, since you could only ever use that value to initialize a type that is=
 layout compatible with an empty class. Namely, another empty class. And em=
pty classes have no value.

### offsetof

`offsetof` will obviously not be affected by stateless subobject members of=
 another type. However, if `offsetof` is applied to a stateless subobject, =
what is the result?

I would suggest that this either be undefined or 0.

# Potential issues

## The Unknown

One of the most difficult aspects of dealing with any form of stateless typ=
e system is that it represents something that is very new and very complica=
ted for C++ to deal with. As such, the wording for this needs to be quite p=
recise and comprehensive, lest we introduce subtle bugs into the standard.

A good spec doctor needs to be involved with the standardization of this fe=
ature.

# Alternative Designs Explored

There has been many alternatives towards achieving the same ends. Every suc=
h alternative has to deal with 2 fundamental rules of the C++ object model:

1. Objects are defined by a region of storage.
2. Two different object instances have different regions of storage.

This current proposal is designed to avoid changes to rule #1. Stateless su=
bobjects in this proposal still have a non-zero size. Instead, changes to r=
ule #2 are made to permit such subobjects to be able to not disturb the lay=
out of their container.

Other alternatives take a different approach to dealing with these rules.

## Magic standard library wrapper type

[This idea](https://groups.google.com/a/isocpp.org/d/msg/std-proposals/sAdq=
ngl8pew/xCjHCLpuAAAJ) is focused on just the specific case of having empty =
classes potentially take up no space in their containing classes.

It would essentially declare a standard library type that is, in the contex=
t of this proposal, something like this:

=09template<typename T>
=09stateless(auto) struct allow_zero_size : public T {...};

It is a wrapper which, when used as an NSDM, will not take up any space in =
its containing object if the given type is empty. And if it is not, then it=
 will.

The theoretical idea behind this is that it doesn't require new syntax. And=
 in that proposal, `allow_zero_size` would not be forbidden from being in a=
rrays or any of the other forbearances that this proposal forbids stateless=
 types from.

This makes the behavior of such a type rather more difficult to specify. Th=
e standard would still need to have changes to allow subobojects which take=
 up no space to work, since users have to be able to get pointers/reference=
s to them and the like. Once that work is done, exactly how you specify tha=
t a subobject takes up no space does not really matter.

# Changelist

## From pre-release v1:

* Clarified that stateless types act like regular empty types in all cases =
except when declared as direct subobjects of classes.

* Explicitly noted that the alignment of stateless subobjects will be respe=
cted by their containers.

# Acknowledgments

From the C++ Future Discussions forum:

* Avi Kivity
* A. Jo=C3=ABl Lamotte, who's original thread on [Inline Classes](https://g=
roups.google.com/a/isocpp.org/d/msg/std-proposals/u35GIuJECcQ/Yorc58iiBwAJ)=
 was the seed for this idea.
* Vicente J. Botet Escriba
* Matt Calabrese
* Andrew Tomazos
* Matthew Woehlke
* Bengt Gustafsson


[^1]: It may be reasonable to use the logical `or` between the two, instead=
 of failing on a mis-match.

[^2]: Yes, it is be possible for an otherwise empty type to use its own `th=
is` pointer as its state. This could be used to register itself with some g=
lobal system or perform some other side-effect. The current rules ensure, e=
ven with EBO, that an empty object instance will always have a distinct `th=
is` pointer from any other instance of that type. However, such types would=
 be inappropriate to use as stateless types, since they are not logically s=
tateless. Further, I find it highly unlikely that such code is sufficiently=
 widespread to be much of a problem. It would be better for makers of such =
classes to simply declare an unused member of type `char`, to prevent thems=
elves from being considered empty.
------=_Part_811_1519885034.1468433911353--

.


Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Wed, 13 Jul 2016 15:35:22 -0700 (PDT)
Raw View
------=_Part_744_1883374240.1468449322584
Content-Type: multipart/alternative;
 boundary="----=_Part_745_692303546.1468449322584"

------=_Part_745_692303546.1468449322584
Content-Type: text/plain; charset=UTF-8

You wrote:

As far as C++ is concerned, if you do `a->v()`, you are accessing the
pointer `a`. Oh, the compiler may not dereference that memory location just
to call the function (unless it's virtual). But this isn't about what
compilers do; it's about what the standard *says*. And `a->v()` is no less
of an access to the pointer `a` than `a->d = 4;` is.

If this is what worries you I think the C++ standard could easily be
changed to allow calling a non-virtual method of a stateless object with
any this pointer. If this solves the "array of stateless objects" issue it
is well worth it.

I understand now that the need for a stateless class came from usages of
new, make_unique and similar where it is hard or impossible to tag the
variable itself as stateless. However, it bothers me a little with this
anyway as malloc() typically returns nullptr if you call it with 0 bytes.
But maybe this can be changed to returning some other fixed address so that
null-testing the pointer returns false. This other address (such as 1)
would then have to be tested for in free() of course. This is a scary
solution, especially as two separate object addresses can now compare
equal. I am skeptical to the possibility of avoiding allocating a minimal
size block for heap use of stateless types. For the new[] case I think a 1
byte allocation would be enough, but is this motivation enough for having
the stateless class possibility?

For static and local variables it seems reasonable to require the stateless
keyword at the variable declaration.

If you ask me we could just as well make all variables stateless(auto),
i.e. I don't see the problem (outside the standard text) of having the same
address of two variables, but everyone else seems convinced that this is a
real problem, and in that case I would be scared to put stateless on a
class and then use it as a template parameter so that the template code
unknowingly generates zero sized variables... It seems that you have to
make up your mind whether aliasing the address of two variables is a
problem or not! I don't think sprinkling the documentation of all libraries
out there with notes on each template whether it is proof for stateless
classes or not is a feasible solution, and then expecting users to read and
follow those notes.







And if you access an invalid pointer, you cause undefined behavior.

--
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/f0fb1ec2-fe41-4daf-a979-7965c90d4468%40isocpp.org.

------=_Part_745_692303546.1468449322584
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div>You wrote:</div><div><br></div><div>As far as C++ is =
concerned, if you do `a-&gt;v()`, you are accessing the pointer `a`. Oh, th=
e compiler may not dereference that memory location just to call the functi=
on (unless it&#39;s virtual). But this isn&#39;t about what compilers do; i=
t&#39;s about what the standard=C2=A0<i>says</i>. And `a-&gt;v()` is no les=
s of an access to the pointer `a` than `a-&gt;d =3D 4;` is.</div><div><br><=
/div><div>If this is what worries you I think the C++ standard could easily=
 be changed to allow calling a non-virtual method of a stateless object wit=
h any this pointer. If this solves the &quot;array of stateless objects&quo=
t; issue it is well worth it.<br></div><div><br></div><div>I understand now=
 that the need for a stateless class came from usages of new, make_unique a=
nd similar where it is hard or impossible to tag the variable itself as sta=
teless. However, it bothers me a little with this anyway as malloc() typica=
lly returns nullptr if you call it with 0 bytes. But maybe this can be chan=
ged to returning some other fixed address so that null-testing the pointer =
returns false. This other address (such as 1) would then have to be tested =
for in free() of course. This is a scary solution, especially as two separa=
te object addresses can now compare equal. I am skeptical to the possibilit=
y of avoiding allocating a minimal size block for heap use of stateless typ=
es. For the new[] case I think a 1 byte allocation would be enough, but is =
this motivation enough for having the stateless class possibility?=C2=A0</d=
iv><div><br></div><div>For static and local variables it seems reasonable t=
o require the stateless keyword at the variable declaration.</div><div><br>=
</div><div>If you ask me we could just as well make all variables stateless=
(auto), i.e. I don&#39;t see the problem (outside the standard text) of hav=
ing the same address of two variables, but everyone else seems convinced th=
at this is a real problem, and in that case I would be scared to put statel=
ess on a class and then use it as a template parameter so that the template=
 code unknowingly generates zero sized variables... It seems that you have =
to make up your mind whether aliasing the address of two variables is a pro=
blem or not! I don&#39;t think sprinkling the documentation of all librarie=
s out there with notes on each template whether it is proof for stateless c=
lasses or not is a feasible solution, and then expecting users to read and =
follow those notes.</div><div><br></div><div><br></div><div><br><div><br><d=
iv><br></div><div><div class=3D"IVILX2C-fd-a"><div tabindex=3D"0" class=3D"=
IVILX2C-tb-P"><div style=3D"overflow: auto;"><div style=3D"max-height: 1000=
0px;"><div dir=3D"ltr"><br></div><div dir=3D"ltr"><br>And if you access an =
invalid pointer, you cause undefined behavior.</div></div></div></div><div>=
</div><div></div></div><div><div class=3D"IVILX2C-fd-a"></div></div><div cl=
ass=3D"IVILX2C-tb-b"><div class=3D"IVILX2C-tb-a IVILX2C-tb-cb"></div></div>=
</div></div></div></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/f0fb1ec2-fe41-4daf-a979-7965c90d4468%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/f0fb1ec2-fe41-4daf-a979-7965c90d4468=
%40isocpp.org</a>.<br />

------=_Part_745_692303546.1468449322584--

------=_Part_744_1883374240.1468449322584--

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Wed, 13 Jul 2016 16:04:56 -0700
Raw View
Em quarta-feira, 13 de julho de 2016, =C3=A0s 15:35:22 PDT, Bengt Gustafsso=
n=20
escreveu:
> As far as C++ is concerned, if you do `a->v()`, you are accessing the=20
> pointer `a`. Oh, the compiler may not dereference that memory location ju=
st=20
> to call the function (unless it's virtual). But this isn't about what
> compilers do; it's about what the standard *says*. And `a->v()` is no les=
s
> of an access to the pointer `a` than `a->d =3D 4;` is.
>=20
> If this is what worries you I think the C++ standard could easily be=20
> changed to allow calling a non-virtual method of a stateless object with=
=20
> any this pointer. If this solves the "array of stateless objects" issue i=
t=20
> is well worth it.

Only if you can't access "this" pointer in a stateless class's non-static=
=20
member function.

We may want to do that anyway, as otherwise the this pointer value could be=
=20
used for keying access in an associative container, which in turn would=20
require two different stateless objects to have different this pointer valu=
es.

That is the same as your concern:

> This is a scary
> solution, especially as two separate object addresses can now compare
> equal. I am skeptical to the possibility of avoiding allocating a minimal
> size block for heap use of stateless types. For the new[] case I think a =
1
> byte allocation would be enough, but is this motivation enough for having
> the stateless class possibility?

--=20
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--=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/50640154.nopyqqKl5g%40tjmaciei-mobl1.

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Wed, 13 Jul 2016 16:25:47 -0700 (PDT)
Raw View
------=_Part_1816_441733347.1468452347658
Content-Type: multipart/alternative;
 boundary="----=_Part_1817_292795319.1468452347658"

------=_Part_1817_292795319.1468452347658
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

On Wednesday, July 13, 2016 at 7:04:59 PM UTC-4, Thiago Macieira wrote:
>
> Em quarta-feira, 13 de julho de 2016, =C3=A0s 15:35:22 PDT, Bengt Gustafs=
son=20
> escreveu:=20
> > As far as C++ is concerned, if you do `a->v()`, you are accessing the=
=20
> > pointer `a`. Oh, the compiler may not dereference that memory location=
=20
> just=20
> > to call the function (unless it's virtual). But this isn't about what=
=20
> > compilers do; it's about what the standard *says*. And `a->v()` is no=
=20
> less=20
> > of an access to the pointer `a` than `a->d =3D 4;` is.=20
> >=20
> > If this is what worries you I think the C++ standard could easily be=20
> > changed to allow calling a non-virtual method of a stateless object wit=
h=20
> > any this pointer. If this solves the "array of stateless objects" issue=
=20
> it=20
> > is well worth it.=20
>
> Only if you can't access "this" pointer in a stateless class's non-static=
=20
> member function.=20
>
> We may want to do that anyway, as otherwise the this pointer value could=
=20
> be=20
> used for keying access in an associative container, which in turn would=
=20
> require two different stateless objects to have different this pointer=20
> values.
>

The problem is that your suggestion makes it impossible to have stateless=
=20
subobjects which were not initially declared that way. And therefore it=20
doesn't actually solve the whole problem we're trying to solve=20
(`std::allocator` would not be able to be used statelessly except via EBO).=
=20
So we're back to the same problem.

It is possible for a user of an empty type to use its `this` pointer value=
=20
as a form of state. However, I feel that the best way to handle this is to=
=20
accept that it can happen. So the question is this: how often do people do=
=20
that sort of thing? How often do people use the location of an empty class=
=20
instance as a key?

And how often is it that this happens within the same empty class=20
containment hierarchy (both as base classes and NSDM)? After all, it will *=
only=20
fail* if a single object contains two instances of the same stateless=20
subobject.

Which suggests a possible solution, actually. We could just forbid allowing=
=20
a type to have more than one stateless subobject of the same type,=20
recursively.

But really, I think it's worth just accepting this particular edge case. I=
=20
think it's reasonable to assume that 99% of empty types do not use `this`=
=20
in this way, and the 1% who do need such identity can just give themselves=
=20
a `char` member.

--=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/08994aed-750a-4f63-a9df-923b4daecb90%40isocpp.or=
g.

------=_Part_1817_292795319.1468452347658
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Wednesday, July 13, 2016 at 7:04:59 PM UTC-4, Thiago Ma=
cieira wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-le=
ft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">Em quarta-feira, =
13 de julho de 2016, =C3=A0s 15:35:22 PDT, Bengt Gustafsson=20
<br>escreveu:
<br>&gt; As far as C++ is concerned, if you do `a-&gt;v()`, you are accessi=
ng the=20
<br>&gt; pointer `a`. Oh, the compiler may not dereference that memory loca=
tion just=20
<br>&gt; to call the function (unless it&#39;s virtual). But this isn&#39;t=
 about what
<br>&gt; compilers do; it&#39;s about what the standard *says*. And `a-&gt;=
v()` is no less
<br>&gt; of an access to the pointer `a` than `a-&gt;d =3D 4;` is.
<br>&gt;=20
<br>&gt; If this is what worries you I think the C++ standard could easily =
be=20
<br>&gt; changed to allow calling a non-virtual method of a stateless objec=
t with=20
<br>&gt; any this pointer. If this solves the &quot;array of stateless obje=
cts&quot; issue it=20
<br>&gt; is well worth it.
<br>
<br>Only if you can&#39;t access &quot;this&quot; pointer in a stateless cl=
ass&#39;s non-static=20
<br>member function.
<br>
<br>We may want to do that anyway, as otherwise the this pointer value coul=
d be=20
<br>used for keying access in an associative container, which in turn would=
=20
<br>require two different stateless objects to have different this pointer =
values.<br></blockquote><br>The problem is that your suggestion makes it im=
possible to have stateless subobjects which were not initially declared tha=
t way. And therefore it doesn&#39;t actually solve the whole problem we&#39=
;re trying to solve (`std::allocator` would not be able to be used stateles=
sly except via EBO). So we&#39;re back to the same problem.<br><br>It is po=
ssible for a user of an empty type to use its `this` pointer value as a for=
m of state. However, I feel that the best way to handle this is to accept t=
hat it can happen. So the question is this: how often do people do that sor=
t of thing? How often do people use the location of an empty class instance=
 as a key?<br><br>And how often is it that this happens within the same emp=
ty class containment hierarchy (both as base classes and NSDM)? After all, =
it will <i>only fail</i> if a single object contains two instances of the s=
ame stateless subobject.<br><br>Which suggests a possible solution, actuall=
y. We could just forbid allowing a type to have more than one stateless sub=
object of the same type, recursively.<br><br>But really, I think it&#39;s w=
orth just accepting this particular edge case. I think it&#39;s reasonable =
to assume that 99% of empty types do not use `this` in this way, and the 1%=
 who do need such identity can just give themselves a `char` member.<br></d=
iv>

<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/08994aed-750a-4f63-a9df-923b4daecb90%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/08994aed-750a-4f63-a9df-923b4daecb90=
%40isocpp.org</a>.<br />

------=_Part_1817_292795319.1468452347658--

------=_Part_1816_441733347.1468452347658--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Wed, 13 Jul 2016 16:33:15 -0700 (PDT)
Raw View
------=_Part_1085_1072277976.1468452795674
Content-Type: multipart/alternative;
 boundary="----=_Part_1086_301256406.1468452795674"

------=_Part_1086_301256406.1468452795674
Content-Type: text/plain; charset=UTF-8

On Wednesday, July 13, 2016 at 6:35:22 PM UTC-4, Bengt Gustafsson wrote:
>
> You wrote:
>
> As far as C++ is concerned, if you do `a->v()`, you are accessing the
> pointer `a`. Oh, the compiler may not dereference that memory location just
> to call the function (unless it's virtual). But this isn't about what
> compilers do; it's about what the standard *says*. And `a->v()` is no
> less of an access to the pointer `a` than `a->d = 4;` is.
>
> If this is what worries you I think the C++ standard could easily be
> changed to allow calling a non-virtual method of a stateless object with
> any this pointer. If this solves the "array of stateless objects" issue it
> is well worth it.
>

Are you familiar enough with this section of the standard to be throwing
around terms like "easily be changed"? The consequences of simply declaring
that you can just make up a pointer to a type, call it, and get valid
behavior (whatever that would mean) are non-trivial. It *certainly* is not
something to be taken lightly.

Also, making such a radical change for the purpose of allowing arrays to
not take up space is just pointless. They're arrays of objects which are
identical *by definition*. Allowing such arrays to not take up space as
subobject members doesn't solve an actual problem.

I understand now that the need for a stateless class came from usages of
> new, make_unique and similar where it is hard or impossible to tag the
> variable itself as stateless.
>

I'm not sure how to explain this any more clearly.

Stateless types only behave differently from non-stateless types when they
are declared as subobjects of class types. In *all other cases*, they
behave no differently from non-stateless types.

Consider this:

stateless struct no_state {};
struct stateful{};

Given those declarations, `sizeof(no_state)` will be a non-zero value. It
will also be the *same* non-zero value as `sizeof(stateful)`. If you
perform `new no_state`, you will allocate `sizeof(no_state)` bytes. If you
overload `operator new` for `no_state`, then you will find that it will get
a size of `sizeof(no_state)`. At no time will there be a zero-sized
allocation.

If you perform `new no_state[25]`, what you get back will be a genuine
array containing 25 actual values of type `no_state`. That array will
consume `25 * sizeof(no_state)` bytes, and that array will act like any
other C++ array. Again, there is no zero-sized allocation, since
`sizeof(no_state)` is a non-zero value.

Stateless types are a *convenience feature* built atop stateless
subobjects. It simply means that, when the type is used to generate a
subobject of a class, then *that subobject* will be a stateless subobject.
Objects of that type generated in all other ways will not be stateless.

It is class subobjects which are stateless. Nothing else. A type is
stateless only in that it declares class subobjects as stateless implicitly.


> If you ask me we could just as well make all variables stateless(auto),
> i.e. I don't see the problem (outside the standard text) of having the same
> address of two variables, but everyone else seems convinced that this is a
> real problem, and in that case I would be scared to put stateless on a
> class and then use it as a template parameter so that the template code
> unknowingly generates zero sized variables... It seems that you have to
> make up your mind whether aliasing the address of two variables is a
> problem or not! I don't think sprinkling the documentation of all libraries
> out there with notes on each template whether it is proof for stateless
> classes or not is a feasible solution, and then expecting users to read and
> follow those notes.
>

I think you're misunderstanding the "aliasing is a problem" issue when it
comes to zero-sized objects.

Yes, it is a problem. But it is one that can be solved with careful
understanding of the rules and with a solid design for the feature. And I
outlined what I believe is such a solution in the section titled "Memory
locations" (as well as array forbearance). We declare that the memory
location for a stateless subobject can be any valid location of the right
size within its containing object. That solves the "object is a region of
storage" rule.

This is also why we don't allow statelessness in non-subobject contexts.

To satisfy aliasing, we would have to extend the aliasing rules to say that
stateless subobjects can alias with any other object. Now, they still must
be *valid* objects, with all the regular C++ rules that requires (thus you
can't just make up a pointer). But a stateless subobject's region of
storage is not unique within its container, nor is it forbidden from
overlapping with other objects.

My issue with your previous proposal on the subject is that you never
actually *addressed* the problem. My proposal does. I can't claim
sufficient knowledge of the problem to be certain that it *fully* addresses
the problem. But I've explained how it does address the problem as I
understand it.

I would hope to see additional commentary on edge cases that I may have
missed.

--
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/0f24f8e6-8646-4ff2-9fd6-03bffcfcaa5a%40isocpp.org.

------=_Part_1086_301256406.1468452795674
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Wednesday, July 13, 2016 at 6:35:22 PM UTC-4, Bengt Gus=
tafsson wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-l=
eft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"=
><div>You wrote:</div><div><br></div><div>As far as C++ is concerned, if yo=
u do `a-&gt;v()`, you are accessing the pointer `a`. Oh, the compiler may n=
ot dereference that memory location just to call the function (unless it&#3=
9;s virtual). But this isn&#39;t about what compilers do; it&#39;s about wh=
at the standard=C2=A0<i>says</i>. And `a-&gt;v()` is no less of an access t=
o the pointer `a` than `a-&gt;d =3D 4;` is.</div><div><br></div><div>If thi=
s is what worries you I think the C++ standard could easily be changed to a=
llow calling a non-virtual method of a stateless object with any this point=
er. If this solves the &quot;array of stateless objects&quot; issue it is w=
ell worth it.<br></div></div></blockquote><div><br>Are you familiar enough =
with this section of the standard to be throwing around terms like &quot;ea=
sily be changed&quot;? The consequences of simply declaring that you can ju=
st make up a pointer to a type, call it, and get valid behavior (whatever t=
hat would mean) are non-trivial. It <i>certainly</i> is not something to be=
 taken lightly.<br><br>Also, making such a radical change for the purpose o=
f allowing arrays to not take up space is just pointless. They&#39;re array=
s of objects which are identical <i>by definition</i>. Allowing such arrays=
 to not take up space as subobject members doesn&#39;t solve an actual prob=
lem.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;marg=
in-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"=
ltr"><div></div><div></div><div>I understand now that the need for a statel=
ess class came from usages of new, make_unique and similar where it is hard=
 or impossible to tag the variable itself as stateless.</div></div></blockq=
uote><div><br>I&#39;m not sure how to explain this any more clearly.<br><br=
>Stateless types only behave differently from non-stateless types when they=
 are declared as subobjects of class types. In <b><i>all other cases</i></b=
>, they behave no differently from non-stateless types.<br><br>Consider thi=
s:<br><br><div class=3D"prettyprint" style=3D"background-color: rgb(250, 25=
0, 250); border-color: rgb(187, 187, 187); border-style: solid; border-widt=
h: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"s=
ubprettyprint"><span style=3D"color: #000;" class=3D"styled-by-prettify">st=
ateless </span><span style=3D"color: #008;" class=3D"styled-by-prettify">st=
ruct</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> no_st=
ate </span><span style=3D"color: #660;" class=3D"styled-by-prettify">{};</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><s=
pan style=3D"color: #008;" class=3D"styled-by-prettify">struct</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"> stateful</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">{};</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"><br></span></div></code></div><=
br>Given those declarations, `sizeof(no_state)` will be a non-zero value. I=
t will also be the <i>same</i> non-zero value as `sizeof(stateful)`. If you=
 perform `new no_state`, you will allocate `sizeof(no_state)` bytes. If you=
 overload `operator new` for `no_state`, then you will find that it will ge=
t a size of `sizeof(no_state)`. At no time will there be a zero-sized alloc=
ation.<br><br>If you perform `new no_state[25]`, what you get back will be =
a genuine array containing 25 actual values of type `no_state`. That array =
will consume `25 * sizeof(no_state)` bytes, and that array will act like an=
y other C++ array. Again, there is no zero-sized allocation, since `sizeof(=
no_state)` is a non-zero value.<br><br>Stateless types are a <i>convenience=
 feature</i> built atop stateless subobjects. It simply means that, when th=
e type is used to generate a subobject of a class, then <b>that subobject</=
b> will be a stateless subobject. Objects of that type generated in all oth=
er ways will not be stateless.<br><br>It is class subobjects which are stat=
eless. Nothing else. A type is stateless only in that it declares class sub=
objects as stateless implicitly.<br>=C2=A0</div><blockquote class=3D"gmail_=
quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pa=
dding-left: 1ex;"><div dir=3D"ltr"><div>If you ask me we could just as well=
 make all variables stateless(auto), i.e. I don&#39;t see the problem (outs=
ide the standard text) of having the same address of two variables, but eve=
ryone else seems convinced that this is a real problem, and in that case I =
would be scared to put stateless on a class and then use it as a template p=
arameter so that the template code unknowingly generates zero sized variabl=
es... It seems that you have to make up your mind whether aliasing the addr=
ess of two variables is a problem or not! I don&#39;t think sprinkling the =
documentation of all libraries out there with notes on each template whethe=
r it is proof for stateless classes or not is a feasible solution, and then=
 expecting users to read and follow those notes.</div></div></blockquote><d=
iv><br>I think you&#39;re misunderstanding the &quot;aliasing is a problem&=
quot; issue when it comes to zero-sized objects.<br><br>Yes, it is a proble=
m. But it is one that can be solved with careful understanding of the rules=
 and with a solid design for the feature. And I outlined what I believe is =
such a solution in the section titled &quot;Memory locations&quot; (as well=
 as array forbearance). We declare that the memory location for a stateless=
 subobject can be any valid location of the right size within its containin=
g object. That solves the &quot;object is a region of storage&quot; rule.<b=
r><br>This is also why we don&#39;t allow statelessness in non-subobject co=
ntexts.<br><br>To satisfy aliasing, we would have to extend the aliasing ru=
les to say that stateless subobjects can alias with any other object. Now, =
they still must be <i>valid</i> objects, with all the regular C++ rules tha=
t requires (thus you can&#39;t just make up a pointer). But a stateless sub=
object&#39;s region of storage is not unique within its container, nor is i=
t forbidden from overlapping with other objects.<br><br>My issue with your =
previous proposal on the subject is that you never actually <i>addressed</i=
> the problem. My proposal does. I can&#39;t claim sufficient knowledge of =
the problem to be certain that it <i>fully</i> addresses the problem. But I=
&#39;ve explained how it does address the problem as I understand it.<br><b=
r>I would hope to see additional commentary on edge cases that I may have m=
issed.<br></div></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/0f24f8e6-8646-4ff2-9fd6-03bffcfcaa5a%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/0f24f8e6-8646-4ff2-9fd6-03bffcfcaa5a=
%40isocpp.org</a>.<br />

------=_Part_1086_301256406.1468452795674--

------=_Part_1085_1072277976.1468452795674--

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Wed, 13 Jul 2016 17:30:16 -0700
Raw View
Em quarta-feira, 13 de julho de 2016, =C3=A0s 16:25:47 PDT, Nicol Bolas esc=
reveu:
> > We may want to do that anyway, as otherwise the this pointer value coul=
d
> > be
> > used for keying access in an associative container, which in turn would
> > require two different stateless objects to have different this pointer
> > values.
>=20
> The problem is that your suggestion makes it impossible to have stateless
> subobjects which were not initially declared that way. And therefore it
> doesn't actually solve the whole problem we're trying to solve
> (`std::allocator` would not be able to be used statelessly except via EBO=
).
> So we're back to the same problem.

Why can't std::allocator be declared in C++2x as stateless?

That would allow the class author to decide whether the class can be used=
=20
statelessly or not. The implementation should not be allowed to use techniq=
ues=20
like EBO for non-stateless classes, as the implementation could very well=
=20
require different pointer addresses for two elements.

Example would be std::tuple<allocator, allocator>.

> It is possible for a user of an empty type to use its `this` pointer valu=
e
> as a form of state. However, I feel that the best way to handle this is t=
o
> accept that it can happen. So the question is this: how often do people d=
o
> that sort of thing? How often do people use the location of an empty clas=
s
> instance as a key?

I know of only two cases, which boil down to not really being stateless. Th=
at=20
is, the object is not really stateless, it's just keeping the data elsewher=
e.

One case is in poorly-designed code that didn't foresee the need to expand =
the=20
class to accommodate. This happened to Qt 3 and KDE 3 classes, when the=20
requirement to always add a d pointer (pimpl) wasn't yet on the coding=20
guidelines. Whenever the class author needed to expand the class, the solut=
ion=20
was to have a global hash that was keyed on the object's address.

You can still find the recommendation in the KDE Wiki:

https://community.kde.org/Policies/Binary_Compatibility_Issues_With_C%2B
%2B#Adding_new_data_members_to_classes_without_d-pointer

The second is when you only want to do that in debug mode, to keep some ext=
ra=20
state that classes don't often do.

> And how often is it that this happens within the same empty class
> containment hierarchy (both as base classes and NSDM)? After all, it will
> *only fail* if a single object contains two instances of the same statele=
ss
> subobject.

Indeed, which can happen for std::tuple<Stateless, Stateless>.

Granted, this is not very common, but why not require class authors to add=
=20
"stateless" ?

> Which suggests a possible solution, actually. We could just forbid allowi=
ng
> a type to have more than one stateless subobject of the same type,
> recursively.
>=20
> But really, I think it's worth just accepting this particular edge case. =
I
> think it's reasonable to assume that 99% of empty types do not use `this`
> in this way, and the 1% who do need such identity can just give themselve=
s
> a `char` member.

They probably should, but we have two options:

1) require "fake stateless" classes to have a member
2) require stateless classes to have a "stateless" keywords

Why not #2?

--=20
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--=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/6252659.1BrsWodJ1t%40tjmaciei-mobl1.

.


Author: jgottman6@gmail.com
Date: Wed, 13 Jul 2016 18:29:18 -0700 (PDT)
Raw View
------=_Part_56_1861764603.1468459759027
Content-Type: multipart/alternative;
 boundary="----=_Part_57_1077874373.1468459759028"

------=_Part_57_1077874373.1468459759028
Content-Type: text/plain; charset=UTF-8



On Wednesday, July 13, 2016 at 6:35:22 PM UTC-4, Bengt Gustafsson wrote:
>
> You wrote:
>
> As far as C++ is concerned, if you do `a->v()`, you are accessing the
> pointer `a`. Oh, the compiler may not dereference that memory location just
> to call the function (unless it's virtual). But this isn't about what
> compilers do; it's about what the standard *says*. And `a->v()` is no
> less of an access to the pointer `a` than `a->d = 4;` is.
>
> If this is what worries you I think the C++ standard could easily be
> changed to allow calling a non-virtual method of a stateless object with
> any this pointer. If this solves the "array of stateless objects" issue it
> is well worth it.
>
>
The main problem with arrays of stateless objects is that, given
stateless Foo fooArray[7];

In the code
for (auto begin = fooArray, end = fooArray + 7; begin != end; ++begin) {
   bar(*begin);
}

the function bar must be called exactly 7 times,  The range-based for loop
depends on this.  If FooArray consists of 7 size 0 objects, how could you
possibly guarantee that?

Joe Gottman

--
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/d88ec6ff-2501-49be-830b-c80033b208dd%40isocpp.org.

------=_Part_57_1077874373.1468459759028
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><br>On Wednesday, July 13, 2016 at 6:35:22 PM UTC-4, B=
engt Gustafsson 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"><div>You wrote:</div><div><br></div><div>As far as C++ is concerne=
d, if you do `a-&gt;v()`, you are accessing the pointer `a`. Oh, the compil=
er may not dereference that memory location just to call the function (unle=
ss it&#39;s virtual). But this isn&#39;t about what compilers do; it&#39;s =
about what the standard=C2=A0<i>says</i>. And `a-&gt;v()` is no less of an =
access to the pointer `a` than `a-&gt;d =3D 4;` is.</div><div><br></div><di=
v>If this is what worries you I think the C++ standard could easily be chan=
ged to allow calling a non-virtual method of a stateless object with any th=
is pointer. If this solves the &quot;array of stateless objects&quot; issue=
 it is well worth it.<br></div><br></div></blockquote><div><br>The main pro=
blem with arrays of stateless objects is that, given<br><div class=3D"prett=
yprint" style=3D"background-color: rgb(250, 250, 250); border-color: rgb(18=
7, 187, 187); border-style: solid; border-width: 1px; word-wrap: break-word=
;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D=
"color: #000;" class=3D"styled-by-prettify">stateless </span><span style=3D=
"color: #606;" class=3D"styled-by-prettify">Foo</span><span style=3D"color:=
 #000;" class=3D"styled-by-prettify"> fooArray</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">[</span><span style=3D"color: #066;" cl=
ass=3D"styled-by-prettify">7</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">];</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"><br></span></div></code></div><br>In the code<br><div class=3D"pr=
ettyprint" style=3D"background-color: rgb(250, 250, 250); border-color: rgb=
(187, 187, 187); border-style: solid; border-width: 1px; word-wrap: break-w=
ord;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span style=
=3D"color: #008;" class=3D"styled-by-prettify">for</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">(</span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">auto</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">begin</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> fooArray</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D=
"color: #008;" class=3D"styled-by-prettify">end</span><span style=3D"color:=
 #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> fooArray </span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">+</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettif=
y">7</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span s=
tyle=3D"color: #008;" class=3D"styled-by-prettify">begin</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">!=3D</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">end</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">+=
+</span><span style=3D"color: #008;" class=3D"styled-by-prettify">begin</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0bar</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">(*</span><span style=3D"color: =
#008;" class=3D"styled-by-prettify">begin</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">}</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"><br></span></div></code></div><br>the function bar must be called =
exactly 7 times,=C2=A0 The range-based for loop depends on this.=C2=A0 If F=
ooArray consists of 7 size 0 objects, how could you possibly guarantee that=
?<br><br>Joe Gottman<br></div></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/d88ec6ff-2501-49be-830b-c80033b208dd%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/d88ec6ff-2501-49be-830b-c80033b208dd=
%40isocpp.org</a>.<br />

------=_Part_57_1077874373.1468459759028--

------=_Part_56_1861764603.1468459759027--

.


Author: Giovanni Piero Deretta <gpderetta@gmail.com>
Date: Thu, 14 Jul 2016 02:37:04 -0700 (PDT)
Raw View
------=_Part_332_1941254222.1468489024640
Content-Type: multipart/alternative;
 boundary="----=_Part_333_1222232117.1468489024640"

------=_Part_333_1222232117.1468489024640
Content-Type: text/plain; charset=UTF-8

On Wednesday, July 13, 2016 at 3:20:22 PM UTC+1, Nicol Bolas wrote:
>
> On Wednesday, July 13, 2016 at 7:03:42 AM UTC-4, Bengt Gustafsson wrote:
>>
>> It seems to me that by requiring that the type of the variable being
>> declared *stateless* really is empty you prevent your new feature from
>> being used in maybe the most common use case exemplified by the container *Alloc
>> *type. What's needed there is a potentially zero-sized member in case
>> the Alloc class is stateless, but which takes up as much space as needed if
>> it is not.
>>
>
> I called that specific case out as an example:
>

[snip predicated stateless example]

`a` will take up no space if `Alloc` is empty. Also, you could use
> `stateless(auto)` instead of the explicit `is_empty_v` test.
>
> This allows you to make a distinction between "Make this object stateless
> where possible" and "If this type is not empty, then that's an error."
> While the former is useful, the latter is also quite useful. After all, if
> your type needs to be empty, and you're including a bunch of other member
> types, you want to make sure nobody breaks your type's rules by
> accidentally adding an NSDM or something.
>
>
What about a conditional 'static' construct? By predicating static on, for
example, 'is_empty' you get similar guarantees. The advantage is that the
object will still be a proper C++ object whit its own address, but with
(conditional) static lifetime, so it will not take space in the object
itself. I'll leave the part of how to make the initialization conditional
in the constructor initializer list to others.



--
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/85d74f4a-9b3f-4614-8c96-74ca12e9d6c2%40isocpp.org.

------=_Part_333_1222232117.1468489024640
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Wednesday, July 13, 2016 at 3:20:22 PM UTC+1, Nicol Bol=
as wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: =
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">On W=
ednesday, July 13, 2016 at 7:03:42 AM UTC-4, Bengt Gustafsson wrote:<blockq=
uote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:=
1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">It seems to me that by re=
quiring that the type of the variable being declared <i>stateless</i> reall=
y is empty you prevent your new feature from being used in maybe the most c=
ommon use case exemplified by the container <i>Alloc </i>type. What&#39;s n=
eeded there is a potentially zero-sized member in case the Alloc class is s=
tateless, but which takes up as much space as needed if it is not.</div></b=
lockquote><div><br>I called that specific case out as an example:<br></div>=
</div></blockquote><div><br>[snip predicated stateless example]<br><br></di=
v><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;b=
order-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div>`a` wi=
ll take up no space if `Alloc` is empty. Also, you could use `stateless(aut=
o)` instead of the explicit `is_empty_v` test.<br><br>This allows you to ma=
ke a distinction between &quot;Make this object stateless where possible&qu=
ot; and &quot;If this type is not empty, then that&#39;s an error.&quot; Wh=
ile the former is useful, the latter is also quite useful. After all, if yo=
ur type needs to be empty, and you&#39;re including a bunch of other member=
 types, you want to make sure nobody breaks your type&#39;s rules by accide=
ntally adding an NSDM or something.</div><br></div></blockquote><div><br>Wh=
at about a conditional &#39;static&#39; construct? By predicating static on=
, for example, &#39;is_empty&#39; you get similar guarantees. The advantage=
 is that the object will still be a proper C++ object whit its own address,=
 but with (conditional) static lifetime, so it will not take space in the o=
bject itself. I&#39;ll leave the part of how to make the initialization con=
ditional in the constructor initializer list to others.<br></div><div><br>=
=C2=A0</div></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/85d74f4a-9b3f-4614-8c96-74ca12e9d6c2%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/85d74f4a-9b3f-4614-8c96-74ca12e9d6c2=
%40isocpp.org</a>.<br />

------=_Part_333_1222232117.1468489024640--

------=_Part_332_1941254222.1468489024640--

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Thu, 14 Jul 2016 08:46:02 -0700
Raw View
On quinta-feira, 14 de julho de 2016 02:37:04 PDT Giovanni Piero Deretta
wrote:
> What about a conditional 'static' construct? By predicating static on, for
> example, 'is_empty' you get similar guarantees. The advantage is that the
> object will still be a proper C++ object whit its own address, but with
> (conditional) static lifetime, so it will not take space in the object
> itself. I'll leave the part of how to make the initialization conditional
> in the constructor initializer list to others.

You replace one problem with the other. Now they have addresses, but two
different objects have the same address.

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--
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/14332330.63NO6F4mBz%40tjmaciei-mobl1.

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Thu, 14 Jul 2016 12:10:56 -0700 (PDT)
Raw View
------=_Part_1026_1742758388.1468523457066
Content-Type: multipart/alternative;
 boundary="----=_Part_1027_556511823.1468523457066"

------=_Part_1027_556511823.1468523457066
Content-Type: text/plain; charset=UTF-8

On Thursday, July 14, 2016 at 5:37:05 AM UTC-4, Giovanni Piero Deretta
wrote:
>
> On Wednesday, July 13, 2016 at 3:20:22 PM UTC+1, Nicol Bolas wrote:
>>
>> On Wednesday, July 13, 2016 at 7:03:42 AM UTC-4, Bengt Gustafsson wrote:
>>>
>>> It seems to me that by requiring that the type of the variable being
>>> declared *stateless* really is empty you prevent your new feature from
>>> being used in maybe the most common use case exemplified by the container *Alloc
>>> *type. What's needed there is a potentially zero-sized member in case
>>> the Alloc class is stateless, but which takes up as much space as needed if
>>> it is not.
>>>
>>
>> I called that specific case out as an example:
>>
>
> [snip predicated stateless example]
>
> `a` will take up no space if `Alloc` is empty. Also, you could use
>> `stateless(auto)` instead of the explicit `is_empty_v` test.
>>
>> This allows you to make a distinction between "Make this object stateless
>> where possible" and "If this type is not empty, then that's an error."
>> While the former is useful, the latter is also quite useful. After all, if
>> your type needs to be empty, and you're including a bunch of other member
>> types, you want to make sure nobody breaks your type's rules by
>> accidentally adding an NSDM or something.
>>
>>
> What about a conditional 'static' construct? By predicating static on, for
> example, 'is_empty' you get similar guarantees. The advantage is that the
> object will still be a proper C++ object whit its own address, but with
> (conditional) static lifetime, so it will not take space in the object
> itself. I'll leave the part of how to make the initialization conditional
> in the constructor initializer list to others.
>

There are two problems there:

1) It's not an NSDM. Which means you can't really treat it like an NSDM.
While you can partially treat it like one, you cannot treat it like one in
all ways. Constructor initialization is part of it, but so are things like
reflection, `offsetof`, member pointers, and so forth.

2) You can't have static base classes. I don't know why people keep
forgetting that EBO is an optimization and therefore not required (for
non-standard layout types).

--
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/09f0adc8-60f3-43c7-8ecf-cf521ac7ff0a%40isocpp.org.

------=_Part_1027_556511823.1468523457066
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Thursday, July 14, 2016 at 5:37:05 AM UTC-4, Giovanni P=
iero Deretta wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;mar=
gin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D=
"ltr">On Wednesday, July 13, 2016 at 3:20:22 PM UTC+1, Nicol Bolas wrote:<b=
lockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-=
left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">On Wednesday, July 1=
3, 2016 at 7:03:42 AM UTC-4, Bengt Gustafsson wrote:<blockquote class=3D"gm=
ail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;p=
adding-left:1ex"><div dir=3D"ltr">It seems to me that by requiring that the=
 type of the variable being declared <i>stateless</i> really is empty you p=
revent your new feature from being used in maybe the most common use case e=
xemplified by the container <i>Alloc </i>type. What&#39;s needed there is a=
 potentially zero-sized member in case the Alloc class is stateless, but wh=
ich takes up as much space as needed if it is not.</div></blockquote><div><=
br>I called that specific case out as an example:<br></div></div></blockquo=
te><div><br>[snip predicated stateless example]<br><br></div><blockquote cl=
ass=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #cc=
c solid;padding-left:1ex"><div dir=3D"ltr"><div>`a` will take up no space i=
f `Alloc` is empty. Also, you could use `stateless(auto)` instead of the ex=
plicit `is_empty_v` test.<br><br>This allows you to make a distinction betw=
een &quot;Make this object stateless where possible&quot; and &quot;If this=
 type is not empty, then that&#39;s an error.&quot; While the former is use=
ful, the latter is also quite useful. After all, if your type needs to be e=
mpty, and you&#39;re including a bunch of other member types, you want to m=
ake sure nobody breaks your type&#39;s rules by accidentally adding an NSDM=
 or something.</div><br></div></blockquote><div><br>What about a conditiona=
l &#39;static&#39; construct? By predicating static on, for example, &#39;i=
s_empty&#39; you get similar guarantees. The advantage is that the object w=
ill still be a proper C++ object whit its own address, but with (conditiona=
l) static lifetime, so it will not take space in the object itself. I&#39;l=
l leave the part of how to make the initialization conditional in the const=
ructor initializer list to others.</div></div></blockquote><div><br>There a=
re two problems there:<br><br>1) It&#39;s not an NSDM. Which means you can&=
#39;t really treat it like an NSDM. While you can partially treat it like o=
ne, you cannot treat it like one in all ways. Constructor initialization is=
 part of it, but so are things like reflection, `offsetof`, member pointers=
, and so forth.<br><br>2) You can&#39;t have static base classes. I don&#39=
;t know why people keep forgetting that EBO is an optimization and therefor=
e not required (for non-standard layout types).<br></div></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/09f0adc8-60f3-43c7-8ecf-cf521ac7ff0a%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/09f0adc8-60f3-43c7-8ecf-cf521ac7ff0a=
%40isocpp.org</a>.<br />

------=_Part_1027_556511823.1468523457066--

------=_Part_1026_1742758388.1468523457066--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Thu, 14 Jul 2016 13:09:36 -0700 (PDT)
Raw View
------=_Part_1051_485314420.1468526976971
Content-Type: multipart/alternative;
 boundary="----=_Part_1052_319949063.1468526976972"

------=_Part_1052_319949063.1468526976972
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

On Wednesday, July 13, 2016 at 8:30:20 PM UTC-4, Thiago Macieira wrote:
>
> Em quarta-feira, 13 de julho de 2016, =C3=A0s 16:25:47 PDT, Nicol Bolas=
=20
> escreveu:=20
> > > We may want to do that anyway, as otherwise the this pointer value=20
> could=20
> > > be=20
> > > used for keying access in an associative container, which in turn=20
> would=20
> > > require two different stateless objects to have different this pointe=
r=20
> > > values.=20
> >=20
> > The problem is that your suggestion makes it impossible to have=20
> stateless=20
> > subobjects which were not initially declared that way. And therefore it=
=20
> > doesn't actually solve the whole problem we're trying to solve=20
> > (`std::allocator` would not be able to be used statelessly except via=
=20
> EBO).=20
> > So we're back to the same problem.=20
>
> Why can't std::allocator be declared in C++2x as stateless?=20
>

Because that would potentially break code. The size of any object that used=
=20
`allocator` as a member variable would change, thus breaking any ABIs=20
involving such objects.

That would allow the class author to decide whether the class can be used=
=20
> statelessly or not. The implementation should not be allowed to use=20
> techniques=20
> like EBO for non-stateless classes, as the implementation could very well=
=20
> require different pointer addresses for two elements.=20
>

> Example would be std::tuple<allocator, allocator>.
>

> > It is possible for a user of an empty type to use its `this` pointer=20
> value=20
> > as a form of state. However, I feel that the best way to handle this is=
=20
> to=20
> > accept that it can happen. So the question is this: how often do people=
=20
> do=20
> > that sort of thing? How often do people use the location of an empty=20
> class=20
> > instance as a key?=20
>
> I know of only two cases, which boil down to not really being stateless.=
=20
> That=20
> is, the object is not really stateless, it's just keeping the data=20
> elsewhere.=20
>
> One case is in poorly-designed code that didn't foresee the need to expan=
d=20
> the=20
> class to accommodate. This happened to Qt 3 and KDE 3 classes, when the=
=20
> requirement to always add a d pointer (pimpl) wasn't yet on the coding=20
> guidelines. Whenever the class author needed to expand the class, the=20
> solution=20
> was to have a global hash that was keyed on the object's address.=20
>
> You can still find the recommendation in the KDE Wiki:=20
>
> https://community.kde.org/Policies/Binary_Compatibility_Issues_With_C%2B=
=20
> %2B#Adding_new_data_members_to_classes_without_d-pointer=20
> <https://community.kde.org/Policies/Binary_Compatibility_Issues_With_C%2B=
%2B#Adding_new_data_members_to_classes_without_d-pointer>=20
>
> The second is when you only want to do that in debug mode, to keep some=
=20
> extra=20
> state that classes don't often do.=20
>
> > And how often is it that this happens within the same empty class=20
> > containment hierarchy (both as base classes and NSDM)? After all, it=20
> will=20
> > *only fail* if a single object contains two instances of the same=20
> stateless=20
> > subobject.=20
>
> Indeed, which can happen for std::tuple<Stateless, Stateless>.
>

Actually, it wouldn't (in my proposal as it currently stands). `tuple` does=
=20
not necessarily have any true subobjects of type `Stateless`. Or rather,=20
that's not a *required* implementation of `tuple`. Some `tuple`=20
implementations use recursive inheritance, while others rely on placement=
=20
`new` gimmicks. In the latter case, the two types would just be empty=20
types, and thus they would have unique memory locations.

Granted, this is not very common, but why not require class authors to add=
=20
> "stateless" ?=20
>
> > Which suggests a possible solution, actually. We could just forbid=20
> allowing=20
> > a type to have more than one stateless subobject of the same type,=20
> > recursively.=20
> >=20
> > But really, I think it's worth just accepting this particular edge case=
..=20
> I=20
> > think it's reasonable to assume that 99% of empty types do not use=20
> `this`=20
> > in this way, and the 1% who do need such identity can just give=20
> themselves=20
> > a `char` member.=20
>
> They probably should, but we have two options:=20
>
> 1) require "fake stateless" classes to have a member=20
> 2) require stateless classes to have a "stateless" keywords=20
>
> Why not #2?
>

I do appreciate the simplicity of #2. It was after all my original design=
=20
from the very first version of this idea=20
<https://groups.google.com/a/isocpp.org/forum/#!searchin/std-proposals/stat=
eless$20inner/std-proposals/HjGujSdKXX0/27WIWTc_EwAJ>.=20
However, remember back to the defining problem for this proposal. Someone=
=20
gives us a type. We want to use that type as a member variable. But if that=
=20
type is empty, we don't want our type taking up extra space.

#2 is not a solution to this problem. Why? Because people will still pass=
=20
us empty-but-not-stateless types. And therefore this:

template<typename Alloc>
struct DataBlock : public Alloc
{};

Will always be a better alternative than this:

template<typename Alloc>
struct DataBlock
{
  Alloc a;
};

In the former, we are guaranteed to avoid bloat for any empty class. In the=
=20
latter, we only avoid bloat if the user provides a stateless type. And=20
stateless types will *always* be a subset of empty types.

The goal of this whole exercise is to allow the latter to be just as=20
efficient as the former, thus ensuring that we only derive from something=
=20
if we really mean it. By only allowing types explicitly declared stateless=
=20
to be used statelessly, we cannot achieve that, since users will always=20
pass empty types that could have been optimized, but aren't.

And it's important to realize that we are not using the type in any way=20
that would break the type's identity. There would never be two stateless=20
subobjects of type `Alloc` in `DataBlock::Alloc`. We are guaranteed that,=
=20
for any two instances of `DataBlock<Alloc>`, their `a` members will have=20
different addresses.

----

I've been thinking quite a bit about the scope of the unique identity=20
problem. I have come up with 3 possible solutions:

1: Ignore it. Basically saying that it's not a problem.

2: Explicit forbid it. I didn't like this idea at first. But then I=20
remembered the increasingly complicated exception in standard layout rules=
=20
<http://en.cppreference.com/w/cpp/concept/StandardLayoutType>. The one=20
which forbids using the same type as a base class more than once, as well=
=20
as the first NSDM (recursively) from being the same type as one of the base=
=20
classes:

struct empty {};

struct not_standard_layout : public empty
{
  empty e;
};

This incredibly complex rule exists to avoid this *exact* problem. If that=
=20
were permitted to be standard layout, then `not_standard_layout::empty`=20
would be at the same address as `not_standard_layout::e`. There would be=20
two overlapping objects of the same type, so the two objects would lose=20
their identity.

Stateless subobjects have often been analogized as a generalized form of=20
empty base optimization. Given that analogy, it makes sense to have a=20
similar rule forbidding such things for stateless subobjects. In this case,=
=20
it would be a hard compile error, since you asked for something to be=20
stateless, but that cannot be provided.

The rules here are very complex however, much as the standard layout=20
exception rule has grown over the years.

3: Redefine the problem away. The problem is essentially this: do stateless=
=20
subobjects have *identity* outside of their containing non-stateless=20
instances? Using solution #2 effectively says "yes" and thereby breaks=20
every time you do something that breaks that identity. However, if we say=
=20
"no", then what we're saying is that if a type contains two stateless=20
subobjects of the same type, then they refer to the same object. Thus, we=
=20
don't have two separate objects; we have two names for the *same* object.

Functionally, it's no different from #1; code that expects a type to have=
=20
identity will still fail. But logically, it makes it more clear what it=20
means to declare a subobject to be stateless.

4: I just came up with this while writing this post. It is effectively a=20
merger of #2 and #3.

In the current version of the proposal, applying `stateless` to a type only=
=20
means that subobject declarations for this type are implicitly declared=20
stateless (and prohibiting potentially confusing uses). We can add=20
something more to this declaration.

If you declare that a type is `stateless`, then you are saying that this=20
type does not have identity. And therefore, it is OK if more than one=20
object of this type has the same address. So this represents a contractual=
=20
obligation on the class writer's part to *not* use the class's `this`=20
pointer with the expectation of object identity. Or, using #3's reasoning,=
=20
two subobjects of this type in the same class (recursively) represent=20
different names for the same object.

However, if the type was empty-but-not-stateless, then we invoke rule #2: a=
=20
type may not have more than one stateless subobject of the same=20
non-stateless type.

For example:

stateless struct no_identity {};
struct empty {};

struct s1
{
  no_identity n1; //Stateless by default
  stateless empty e1; //Explicitly stateless.
  no_identity n2; //OK, n1 and n2 are aliases of the same object.
  stateless empty e2; //il-formed. `empty` was not declared `stateless`,=20
and therefore it must have identity.
};

--=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/ec7d33ef-516c-4690-962a-549ddd7092d9%40isocpp.or=
g.

------=_Part_1052_319949063.1468526976972
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Wednesday, July 13, 2016 at 8:30:20 PM UTC-4, Thiago Ma=
cieira wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-le=
ft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">Em quarta-feira, =
13 de julho de 2016, =C3=A0s 16:25:47 PDT, Nicol Bolas escreveu:
<br>&gt; &gt; We may want to do that anyway, as otherwise the this pointer =
value could
<br>&gt; &gt; be
<br>&gt; &gt; used for keying access in an associative container, which in =
turn would
<br>&gt; &gt; require two different stateless objects to have different thi=
s pointer
<br>&gt; &gt; values.
<br>&gt;=20
<br>&gt; The problem is that your suggestion makes it impossible to have st=
ateless
<br>&gt; subobjects which were not initially declared that way. And therefo=
re it
<br>&gt; doesn&#39;t actually solve the whole problem we&#39;re trying to s=
olve
<br>&gt; (`std::allocator` would not be able to be used statelessly except =
via EBO).
<br>&gt; So we&#39;re back to the same problem.
<br>
<br>Why can&#39;t std::allocator be declared in C++2x as stateless?
<br></blockquote><div><br>Because that would potentially break code. The si=
ze of any object that used `allocator` as a member variable would change, t=
hus breaking any ABIs involving such objects.<br><br></div><blockquote clas=
s=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #c=
cc solid;padding-left: 1ex;">
That would allow the class author to decide whether the class can be used=
=20
<br>statelessly or not. The implementation should not be allowed to use tec=
hniques=20
<br>like EBO for non-stateless classes, as the implementation could very we=
ll=20
<br>require different pointer addresses for two elements. <br></blockquote>=
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bor=
der-left: 1px #ccc solid;padding-left: 1ex;">
<br>Example would be std::tuple&lt;allocator, allocator&gt;.<br></blockquot=
e><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;b=
order-left: 1px #ccc solid;padding-left: 1ex;">
<br>&gt; It is possible for a user of an empty type to use its `this` point=
er value
<br>&gt; as a form of state. However, I feel that the best way to handle th=
is is to
<br>&gt; accept that it can happen. So the question is this: how often do p=
eople do
<br>&gt; that sort of thing? How often do people use the location of an emp=
ty class
<br>&gt; instance as a key?
<br>
<br>I know of only two cases, which boil down to not really being stateless=
.. That=20
<br>is, the object is not really stateless, it&#39;s just keeping the data =
elsewhere.
<br>
<br>One case is in poorly-designed code that didn&#39;t foresee the need to=
 expand the=20
<br>class to accommodate. This happened to Qt 3 and KDE 3 classes, when the=
=20
<br>requirement to always add a d pointer (pimpl) wasn&#39;t yet on the cod=
ing=20
<br>guidelines. Whenever the class author needed to expand the class, the s=
olution=20
<br>was to have a global hash that was keyed on the object&#39;s address.
<br>
<br>You can still find the recommendation in the KDE Wiki:
<br>
<br><a href=3D"https://community.kde.org/Policies/Binary_Compatibility_Issu=
es_With_C%2B%2B#Adding_new_data_members_to_classes_without_d-pointer" targe=
t=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.href=3D&#39;https://www.g=
oogle.com/url?q\x3dhttps%3A%2F%2Fcommunity.kde.org%2FPolicies%2FBinary_Comp=
atibility_Issues_With_C%252B%252B%23Adding_new_data_members_to_classes_with=
out_d-pointer\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNEgu2Kz4yE9f2cfo17rJIa=
7cL-18Q&#39;;return true;" onclick=3D"this.href=3D&#39;https://www.google.c=
om/url?q\x3dhttps%3A%2F%2Fcommunity.kde.org%2FPolicies%2FBinary_Compatibili=
ty_Issues_With_C%252B%252B%23Adding_new_data_members_to_classes_without_d-p=
ointer\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNEgu2Kz4yE9f2cfo17rJIa7cL-18Q=
&#39;;return true;">https://community.kde.org/<wbr>Policies/Binary_Compatib=
ility_<wbr>Issues_With_C%2B
<br>%2B#Adding_new_data_members_<wbr>to_classes_without_d-pointer</a>
<br>
<br>The second is when you only want to do that in debug mode, to keep some=
 extra=20
<br>state that classes don&#39;t often do.
<br>
<br>&gt; And how often is it that this happens within the same empty class
<br>&gt; containment hierarchy (both as base classes and NSDM)? After all, =
it will
<br>&gt; *only fail* if a single object contains two instances of the same =
stateless
<br>&gt; subobject.
<br>
<br>Indeed, which can happen for std::tuple&lt;Stateless, Stateless&gt;.<br=
></blockquote><div><br>Actually, it wouldn&#39;t (in my proposal as it curr=
ently stands). `tuple` does not necessarily have any true subobjects of typ=
e `Stateless`. Or rather, that&#39;s not a *required* implementation of `tu=
ple`. Some `tuple` implementations use recursive inheritance, while others =
rely on placement `new` gimmicks. In the latter case, the two types would j=
ust be empty types, and thus they would have unique memory locations.<br><b=
r></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0=
..8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
Granted, this is not very common, but why not require class authors to add=
=20
<br>&quot;stateless&quot; ?
<br>
<br>&gt; Which suggests a possible solution, actually. We could just forbid=
 allowing
<br>&gt; a type to have more than one stateless subobject of the same type,
<br>&gt; recursively.
<br>&gt;=20
<br>&gt; But really, I think it&#39;s worth just accepting this particular =
edge case. I
<br>&gt; think it&#39;s reasonable to assume that 99% of empty types do not=
 use `this`
<br>&gt; in this way, and the 1% who do need such identity can just give th=
emselves
<br>&gt; a `char` member.
<br>
<br>They probably should, but we have two options:
<br>
<br>1) require &quot;fake stateless&quot; classes to have a member
<br>2) require stateless classes to have a &quot;stateless&quot; keywords
<br>
<br>Why not #2?<br></blockquote><div><br>I do appreciate the simplicity of =
#2. It was after all <a href=3D"https://groups.google.com/a/isocpp.org/foru=
m/#!searchin/std-proposals/stateless$20inner/std-proposals/HjGujSdKXX0/27WI=
WTc_EwAJ">my original design from the very first version of this idea</a>. =
However, remember back to the defining problem for this proposal. Someone g=
ives us a type. We want to use that type as a member variable. But if that =
type is empty, we don&#39;t want our type taking up extra space.<br><br>#2 =
is not a solution to this problem. Why? Because people will still pass us e=
mpty-but-not-stateless types. And therefore this:<br><br><div class=3D"pret=
typrint" style=3D"background-color: rgb(250, 250, 250); border-color: rgb(1=
87, 187, 187); border-style: solid; border-width: 1px; word-wrap: break-wor=
d;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span style=
=3D"color: #008;" class=3D"styled-by-prettify">template</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">&lt;</span><span style=3D"co=
lor: #008;" class=3D"styled-by-prettify">typename</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #606;"=
 class=3D"styled-by-prettify">Alloc</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">&gt;</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"><br></span><span style=3D"color: #008;" class=3D"styled-=
by-prettify">struct</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> </span><span style=3D"color: #606;" class=3D"styled-by-prettify">=
DataBlock</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">:</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">public</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #6=
06;" class=3D"styled-by-prettify">Alloc</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">{};</span></div></code></div><br>Will always be a b=
etter alternative than this:<br><br><div class=3D"prettyprint" style=3D"bac=
kground-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border=
-style: solid; border-width: 1px; word-wrap: break-word;"><code class=3D"pr=
ettyprint"><div class=3D"subprettyprint"><span style=3D"color: #008;" class=
=3D"styled-by-prettify">template</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">&lt;</span><span style=3D"color: #008;" class=3D"st=
yled-by-prettify">typename</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> </span><span style=3D"color: #606;" class=3D"styled-by-pre=
ttify">Alloc</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=
</span><span style=3D"color: #008;" class=3D"styled-by-prettify">struct</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span =
style=3D"color: #606;" class=3D"styled-by-prettify">DataBlock</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br>=C2=A0 </span><span style=3D"colo=
r: #606;" class=3D"styled-by-prettify">Alloc</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> a</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"><br></span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">};</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"><br></span></div></code></div><br>In the former, we are guaranteed to av=
oid bloat for any empty class. In the latter, we only avoid bloat if the us=
er provides a stateless type. And stateless types will <i>always</i> be a s=
ubset of empty types.<br><br>The goal of this whole exercise is to allow th=
e latter to be just as efficient as the former, thus ensuring that we only =
derive from something if we really mean it. By only allowing types explicit=
ly declared stateless to be used statelessly, we cannot achieve that, since=
 users will always pass empty types that could have been optimized, but are=
n&#39;t.<br><br>And it&#39;s important to realize that we are not using the=
 type in any way that would break the=20
type&#39;s identity. There would never be two stateless subobjects of type=
=20
`Alloc` in `DataBlock::Alloc`. We are guaranteed that, for any two instance=
s of `DataBlock&lt;Alloc&gt;`, their `a` members will have different addres=
ses.<br><br>----<br><br>I&#39;ve been thinking quite a bit about the scope =
of the unique identity problem. I have come up with 3 possible solutions:<b=
r><br>1: Ignore it. Basically saying that it&#39;s not a problem.<br><br>2:=
 Explicit forbid it. I didn&#39;t like this idea at first. But then I remem=
bered the increasingly complicated exception in <a href=3D"http://en.cppref=
erence.com/w/cpp/concept/StandardLayoutType">standard layout rules</a>. The=
 one which forbids using the same type as a base class more than once, as w=
ell as the first NSDM (recursively) from being the same type as one of the =
base classes:<br><br><div class=3D"prettyprint" style=3D"background-color: =
rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-style: solid; =
border-width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div=
 class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">struct</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> empty </span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">{};</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><=
br></span><span style=3D"color: #008;" class=3D"styled-by-prettify">struct<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> not_standa=
rd_layout </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
:</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><=
span style=3D"color: #008;" class=3D"styled-by-prettify">public</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify"> empty<br></span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 empty e</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color:=
 #660;" class=3D"styled-by-prettify">};</span></div></code></div><br>This i=
ncredibly complex rule exists to avoid this <i>exact</i> problem. If that w=
ere permitted to be standard layout, then `not_standard_layout::empty` woul=
d be at the same address as `not_standard_layout::e`. There would be two ov=
erlapping objects of the same type, so the two objects would lose their ide=
ntity.<br><br>Stateless subobjects have often been analogized as a generali=
zed form of empty base optimization. Given that analogy, it makes sense to =
have a similar rule forbidding such things for stateless subobjects. In thi=
s case, it would be a hard compile error, since you asked for something to =
be stateless, but that cannot be provided.<br><br>The rules here are very c=
omplex however, much as the standard layout exception rule has grown over t=
he years.<br><br>3: Redefine the problem away. The problem is essentially t=
his: do stateless subobjects have <i>identity</i> outside of their containi=
ng non-stateless instances? Using solution #2 effectively says &quot;yes&qu=
ot; and thereby breaks every time you do something that breaks that identit=
y. However, if we say &quot;no&quot;, then what we&#39;re saying is that if=
 a type contains two stateless subobjects of the same type, then they refer=
 to the same object. Thus, we don&#39;t have two separate objects; we have =
two names for the <i>same</i> object.<br><br>Functionally, it&#39;s no diff=
erent from #1; code that expects a type to have identity will still fail. B=
ut logically, it makes it more clear what it means to declare a subobject t=
o be stateless.<br><br>4: I just came up with this while writing this post.=
 It is effectively a merger of #2 and #3.<br><br>In the current version of =
the proposal, applying `stateless` to a type only means that subobject decl=
arations for this type are implicitly declared stateless (and prohibiting p=
otentially confusing uses). We can add something more to this declaration.<=
br><br>If you declare that a type is `stateless`, then you are saying that =
this type does not have identity. And therefore, it is OK if more than one =
object of this type has the same address. So this represents a contractual =
obligation on the class writer&#39;s part to <i>not</i> use the class&#39;s=
 `this` pointer with the expectation of object identity. Or, using #3&#39;s=
 reasoning, two subobjects of this type in the same class (recursively) rep=
resent different names for the same object.<br><br>However, if the type was=
 empty-but-not-stateless, then we invoke rule #2: a type may not have more =
than one stateless subobject of the same non-stateless type.<br><br>For exa=
mple:<br><br><div class=3D"prettyprint" style=3D"background-color: rgb(250,=
 250, 250); border-color: rgb(187, 187, 187); border-style: solid; border-w=
idth: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=
=3D"subprettyprint"><span style=3D"color: #000;" class=3D"styled-by-prettif=
y">stateless </span><span style=3D"color: #008;" class=3D"styled-by-prettif=
y">struct</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
no_identity </span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">{};</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><=
/span><span style=3D"color: #008;" class=3D"styled-by-prettify">struct</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> empty </span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">{};</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br><br></span><span styl=
e=3D"color: #008;" class=3D"styled-by-prettify">struct</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"> s1<br></span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"><br>=C2=A0 no_identity n1</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #800;" =
class=3D"styled-by-prettify">//Stateless by default</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"><br>=C2=A0 stateless empty e1</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"c=
olor: #800;" class=3D"styled-by-prettify">//Explicitly stateless.</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 no_identi=
ty n2</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span =
style=3D"color: #800;" class=3D"styled-by-prettify">//OK, n1 and n2 are ali=
ases of the same object.</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify"><br>=C2=A0 stateless empty e2</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #800;" class=3D"style=
d-by-prettify">//il-formed. `empty` was not declared `stateless`, and there=
fore it must have identity.</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"><br></span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">};</span></div></code></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&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/ec7d33ef-516c-4690-962a-549ddd7092d9%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/ec7d33ef-516c-4690-962a-549ddd7092d9=
%40isocpp.org</a>.<br />

------=_Part_1052_319949063.1468526976972--

------=_Part_1051_485314420.1468526976971--

.


Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
Date: Thu, 14 Jul 2016 13:27:54 -0700 (PDT)
Raw View
------=_Part_1306_607983053.1468528074637
Content-Type: multipart/alternative;
 boundary="----=_Part_1307_1728357297.1468528074637"

------=_Part_1307_1728357297.1468528074637
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

On Wednesday, July 13, 2016 at 3:35:22 PM UTC-7, Bengt Gustafsson wrote:
> You wrote:
>>
>> As far as C++ is concerned, if you do `a->v()`, you are accessing the=20
pointer `a`. Oh, the compiler may not dereference
>> that memory location just to call the function (unless it's virtual).=20
But this isn't about what compilers do; it's about what
>> the standard says. And `a->v()` is no less of an access to the pointer=
=20
`a` than `a->d =3D 4;` is.
>
> If this is what worries you I think the C++ standard could easily be=20
changed to allow calling a non-virtual method of a
> stateless object with any this pointer. If this solves the "array of=20
stateless objects" issue it is well worth it.

I've thought of this too, but I don't think it's feasible. Consider that=20
right now member functions and free functions are basically interchangeable=
:

    class A {
      void f() { return g(this); }
    };
    void g(A *a) { return a->f(); }

You're proposing to make it legal to call garbage->f() (where garbage is=20
e.g. a null pointer, or a pointer that has recently been deleted, or=20
whatever); but not legal to call g(garbage) =E2=80=94 which means that garb=
age->f()=20
will blow up when it gets to the line g(this) anyway.

This trap-for-the-unwary will be both catastrophic for newbies and=20
unnecessarily annoying for experts.  "What do you mean, I have to rewrite=
=20
all my free functions as member functions or else the compiler quietly=20
gives my code undefined behavior??"


On another angle of the topic, it occurred to me the other day that if a=20
programmer is trying to express the idea of "This object has no address =E2=
=80=94=20
that is, I promise not to take its address except perhaps implicitly in=20
trivial ways" =E2=80=94 the most natural way to express that is with the ne=
wly=20
freed-up register storage class.  The meaning of this storage-class=20
specifier in C and C++-pre-17 is *literally* "I promise not to take this=20
object's address", so, if we can piggyback on that intuition, that would be=
=20
nice.  However, this is merely a contribution to the *syntactic* bikeshed;=
=20
I agree with Nicol that there's no obvious forward progress on the=20
*semantic* problem happening here.

my $.02,
=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/3843dfd7-631d-43a1-a568-5220c247140b%40isocpp.or=
g.

------=_Part_1307_1728357297.1468528074637
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Wednesday, July 13, 2016 at 3:35:22 PM UTC-7, Bengt Gus=
tafsson wrote:<br>&gt; You wrote:<br>&gt;&gt;<br>&gt;&gt;=C2=A0As far as C+=
+ is concerned, if you do `a-&gt;v()`, you are accessing the pointer `a`. O=
h, the compiler may not dereference<div>&gt;&gt; that memory location just =
to call the function (unless it&#39;s virtual). But this isn&#39;t about wh=
at compilers do; it&#39;s about what</div><div>&gt;&gt; the standard says. =
And `a-&gt;v()` is no less of an access to the pointer `a` than `a-&gt;d =
=3D 4;` is.<br>&gt;<br>&gt;=C2=A0If this is what worries you I think the C+=
+ standard could easily be changed to allow calling a non-virtual method of=
 a</div><div>&gt; stateless object with any this pointer. If this solves th=
e &quot;array of stateless objects&quot; issue it is well worth it.<br><br>=
I&#39;ve thought of this too, but I don&#39;t think it&#39;s feasible. Cons=
ider that right now member functions and free functions are basically inter=
changeable:</div><div><br></div><div><font face=3D"courier new, monospace">=
=C2=A0 =C2=A0 class A {</font></div><div><font face=3D"courier new, monospa=
ce">=C2=A0 =C2=A0 =C2=A0 void f() { return g(this); }</font></div><div><fon=
t face=3D"courier new, monospace">=C2=A0 =C2=A0 };<br></font></div><div><fo=
nt face=3D"courier new, monospace">=C2=A0 =C2=A0 void g(A *a) { return a-&g=
t;f(); }</font><br></div><div><br></div><div>You&#39;re proposing to make i=
t legal to call <font face=3D"courier new, monospace">garbage-&gt;f()</font=
> (where <font face=3D"courier new, monospace">garbage</font> is e.g. a nul=
l pointer, or a pointer that has recently been deleted, or whatever); but n=
ot legal to call <font face=3D"courier new, monospace">g(garbage)</font> =
=E2=80=94 which means that <font face=3D"courier new, monospace">garbage-&g=
t;f()</font> will blow up when it gets to the line <font face=3D"courier ne=
w, monospace">g(this)</font> anyway.<br><br>This trap-for-the-unwary will b=
e both catastrophic for newbies and unnecessarily annoying for experts. =C2=
=A0&quot;What do you mean, I have to rewrite all my free functions as membe=
r functions or else the compiler quietly gives my code undefined behavior??=
&quot;</div><div><br></div><div><br></div><div>On another angle of the topi=
c, it occurred to me the other day that if a programmer is trying to expres=
s the idea of &quot;This object has no address =E2=80=94 that is, I promise=
 not to take its address except perhaps implicitly in trivial ways&quot; =
=E2=80=94 the most natural way to express that is with the newly freed-up <=
font face=3D"courier new, monospace">register</font> storage class. =C2=A0T=
he meaning of this storage-class specifier in C and C++-pre-17 is <i>litera=
lly</i> &quot;I promise not to take this object&#39;s address&quot;, so, if=
 we can piggyback on that intuition, that would be nice. =C2=A0However, thi=
s is merely a contribution to the <i>syntactic</i> bikeshed; I agree with N=
icol that there&#39;s no obvious forward progress on the <i>semantic</i> pr=
oblem happening here.</div><div><br></div><div>my $.02,<br>=E2=80=93Arthur<=
blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bord=
er-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><div><div=
><div><div></div><div></div></div><div><div></div></div><div><div></div></d=
iv></div></div></div></div></blockquote></div></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/3843dfd7-631d-43a1-a568-5220c247140b%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/3843dfd7-631d-43a1-a568-5220c247140b=
%40isocpp.org</a>.<br />

------=_Part_1307_1728357297.1468528074637--

------=_Part_1306_607983053.1468528074637--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Thu, 14 Jul 2016 13:35:16 -0700 (PDT)
Raw View
------=_Part_933_1957245431.1468528516742
Content-Type: multipart/alternative;
 boundary="----=_Part_934_1526472379.1468528516742"

------=_Part_934_1526472379.1468528516742
Content-Type: text/plain; charset=UTF-8

On Thursday, July 14, 2016 at 4:27:54 PM UTC-4, Arthur O'Dwyer wrote:
>
> However, this is merely a contribution to the *syntactic* bikeshed; I
> agree with Nicol that there's no obvious forward progress on the
> *semantic* problem happening here.
>

I think we are getting somewhere on the semantic issues. We've uncovered
yet another problem to be resolved: the unique identity of such subobjects.
This is separate from aliasing, as that is about objects of different types
overlapping. This one is about different object instances having the same
address.

The only way we're going to solve this problem is to uncover all of the
corner cases and just work out solutions to them.

--
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/ed4f4b19-dfa4-4e8c-b796-d5b1a11c482b%40isocpp.org.

------=_Part_934_1526472379.1468528516742
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Thursday, July 14, 2016 at 4:27:54 PM UTC-4, Arthur O&#=
39;Dwyer 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=
">However, this is merely a contribution to the <i>syntactic</i> bikeshed; =
I agree with Nicol that there&#39;s no obvious forward progress on the <i>s=
emantic</i> problem happening here.</div></blockquote><div><br>I think we a=
re getting somewhere on the semantic issues. We&#39;ve uncovered yet anothe=
r problem to be resolved: the unique identity of such subobjects. This is s=
eparate from aliasing, as that is about objects of different types overlapp=
ing. This one is about different object instances having the same address.<=
br><br>The only way we&#39;re going to solve this problem is to uncover all=
 of the corner cases and just work out solutions to them.<br></div></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/ed4f4b19-dfa4-4e8c-b796-d5b1a11c482b%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/ed4f4b19-dfa4-4e8c-b796-d5b1a11c482b=
%40isocpp.org</a>.<br />

------=_Part_934_1526472379.1468528516742--

------=_Part_933_1957245431.1468528516742--

.


Author: Tom Honermann <tom@honermann.net>
Date: Thu, 14 Jul 2016 17:13:57 -0400
Raw View
This is a multi-part message in MIME format.
--------------35CB79B7099D576BE271BE31
Content-Type: text/plain; charset=UTF-8; format=flowed

On 7/14/2016 4:09 PM, Nicol Bolas wrote:
>
> For example:
>
> |
> stateless structno_identity {};
> structempty {};
>
> structs1
> {
>   no_identity n1;//Stateless by default
>   stateless empty e1;//Explicitly stateless.
>   no_identity n2;//OK, n1 and n2 are aliases of the same object.
>   stateless empty e2;//il-formed. `empty` was not declared
> `stateless`, and therefore it must have identity.
> };
> |
>
I've been thinking along these lines too.  The questions I have are:
* What if no_identify has a non-trivial constructor or destructor. When
are they invoked in the example above and how many times?
* What is the lifetime of the object aliased by n1 and n2 above?
(Essentially the same question).

Tom.

--
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/172ed4c0-9b9a-9b7b-403f-0d787fe7a2db%40honermann.net.

--------------35CB79B7099D576BE271BE31
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<html>
  <head>
    <meta content=3D"text/html; charset=3Dutf-8" http-equiv=3D"Content-Type=
">
  </head>
  <body bgcolor=3D"#FFFFFF" text=3D"#000000">
    <div class=3D"moz-cite-prefix">On 7/14/2016 4:09 PM, Nicol Bolas
      wrote:<br>
    </div>
    <blockquote
      cite=3D"mid:ec7d33ef-516c-4690-962a-549ddd7092d9@isocpp.org"
      type=3D"cite">
      <div dir=3D"ltr"><br>
        <div>For example:<br>
          <br>
          <div class=3D"prettyprint" style=3D"background-color: rgb(250,
            250, 250); border-color: rgb(187, 187, 187); border-style:
            solid; border-width: 1px; word-wrap: break-word;"><code
              class=3D"prettyprint">
              <div class=3D"subprettyprint"><span style=3D"color: #000;"
                  class=3D"styled-by-prettify">stateless </span><span
                  style=3D"color: #008;" class=3D"styled-by-prettify">struc=
t</span><span
                  style=3D"color: #000;" class=3D"styled-by-prettify">
                  no_identity </span><span style=3D"color: #660;"
                  class=3D"styled-by-prettify">{};</span><span
                  style=3D"color: #000;" class=3D"styled-by-prettify"><br>
                </span><span style=3D"color: #008;"
                  class=3D"styled-by-prettify">struct</span><span
                  style=3D"color: #000;" class=3D"styled-by-prettify"> empt=
y
                </span><span style=3D"color: #660;"
                  class=3D"styled-by-prettify">{};</span><span
                  style=3D"color: #000;" class=3D"styled-by-prettify"><br>
                  <br>
                </span><span style=3D"color: #008;"
                  class=3D"styled-by-prettify">struct</span><span
                  style=3D"color: #000;" class=3D"styled-by-prettify"> s1<b=
r>
                </span><span style=3D"color: #660;"
                  class=3D"styled-by-prettify">{</span><span style=3D"color=
:
                  #000;" class=3D"styled-by-prettify"><br>
                  =C2=A0 no_identity n1</span><span style=3D"color: #660;"
                  class=3D"styled-by-prettify">;</span><span style=3D"color=
:
                  #000;" class=3D"styled-by-prettify"> </span><span
                  style=3D"color: #800;" class=3D"styled-by-prettify">//Sta=
teless
                  by default</span><span style=3D"color: #000;"
                  class=3D"styled-by-prettify"><br>
                  =C2=A0 stateless empty e1</span><span style=3D"color: #66=
0;"
                  class=3D"styled-by-prettify">;</span><span style=3D"color=
:
                  #000;" class=3D"styled-by-prettify"> </span><span
                  style=3D"color: #800;" class=3D"styled-by-prettify">//Exp=
licitly
                  stateless.</span><span style=3D"color: #000;"
                  class=3D"styled-by-prettify"><br>
                  =C2=A0 no_identity n2</span><span style=3D"color: #660;"
                  class=3D"styled-by-prettify">;</span><span style=3D"color=
:
                  #000;" class=3D"styled-by-prettify"> </span><span
                  style=3D"color: #800;" class=3D"styled-by-prettify">//OK,
                  n1 and n2 are aliases of the same object.</span><span
                  style=3D"color: #000;" class=3D"styled-by-prettify"><br>
                  =C2=A0 stateless empty e2</span><span style=3D"color: #66=
0;"
                  class=3D"styled-by-prettify">;</span><span style=3D"color=
:
                  #000;" class=3D"styled-by-prettify"> </span><span
                  style=3D"color: #800;" class=3D"styled-by-prettify">//il-=
formed.
                  `empty` was not declared `stateless`, and therefore it
                  must have identity.</span><span style=3D"color: #000;"
                  class=3D"styled-by-prettify"><br>
                </span><span style=3D"color: #660;"
                  class=3D"styled-by-prettify">};</span></div>
            </code></div>
          <br>
        </div>
      </div>
    </blockquote>
    I've been thinking along these lines too.=C2=A0 The questions I have ar=
e:<br>
    * What if no_identify has a non-trivial constructor or destructor.=C2=
=A0
    When are they invoked in the example above and how many times?<br>
    * What is the lifetime of the object aliased by n1 and n2 above?=C2=A0
    (Essentially the same question).<br>
    <br>
    Tom.<br>
  </body>
</html>

<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/172ed4c0-9b9a-9b7b-403f-0d787fe7a2db%=
40honermann.net?utm_medium=3Demail&utm_source=3Dfooter">https://groups.goog=
le.com/a/isocpp.org/d/msgid/std-proposals/172ed4c0-9b9a-9b7b-403f-0d787fe7a=
2db%40honermann.net</a>.<br />

--------------35CB79B7099D576BE271BE31--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Thu, 14 Jul 2016 14:45:00 -0700 (PDT)
Raw View
------=_Part_1539_2133550709.1468532700326
Content-Type: multipart/alternative;
 boundary="----=_Part_1540_1747713128.1468532700326"

------=_Part_1540_1747713128.1468532700326
Content-Type: text/plain; charset=UTF-8

On Thursday, July 14, 2016 at 5:14:03 PM UTC-4, Tom Honermann wrote:
>
> On 7/14/2016 4:09 PM, Nicol Bolas wrote:
>
>
> For example:
>
> stateless struct no_identity {};
> struct empty {};
>
> struct s1
> {
>   no_identity n1; //Stateless by default
>   stateless empty e1; //Explicitly stateless.
>   no_identity n2; //OK, n1 and n2 are aliases of the same object.
>   stateless empty e2; //il-formed. `empty` was not declared `stateless`,
> and therefore it must have identity.
> };
>
> I've been thinking along these lines too.  The questions I have are:
> * What if no_identify has a non-trivial constructor or destructor.  When
> are they invoked in the example above and how many times?
>
* What is the lifetime of the object aliased by n1 and n2 above?
> (Essentially the same question).
>

Well, if there truly is only one `no_identity` subobject in `s1`, then by
definition there must be only one constructor and destructor call. Any
other compiler-generated per-subobject functions (copy/move assignment,
etc) must similarly find only one subobject.

Then again, if the type is truly `stateless` and therefore has no identity,
there would be nothing wrong on an implementation level with declaring that
the per-subobject functions get called once per member. But that plays
havoc with C++'s object rules, since you would be calling a constructor
multiple times on an object who's lifetime has started. Or a destructor
multiple times on the same object.

Then again, we can change the lifetime rules of stateless types (since
they're explicitly denoted as such) to be different. That calling a
constructor on the same stateless object does not restart its lifetime or
calling the destructor multiple times does not end it. Or something like
that.

It's certainly something to consider.

--
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/459db2af-7010-4247-9ec0-8dc26261c8b9%40isocpp.org.

------=_Part_1540_1747713128.1468532700326
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Thursday, July 14, 2016 at 5:14:03 PM UTC-4, Tom Honerm=
ann wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:=
 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
 =20
   =20
 =20
  <div>
    <div>On 7/14/2016 4:09 PM, Nicol Bolas
      wrote:<br>
    </div>
    <blockquote type=3D"cite">
      <div dir=3D"ltr"><br>
        <div>For example:<br>
          <br>
          <div style=3D"background-color:rgb(250,250,250);border-color:rgb(=
187,187,187);border-style:solid;border-width:1px;word-wrap:break-word"><cod=
e>
              <div><span style=3D"color:#000">stateless </span><span style=
=3D"color:#008">struct</span><span style=3D"color:#000">
                  no_identity </span><span style=3D"color:#660">{};</span><=
span style=3D"color:#000"><br>
                </span><span style=3D"color:#008">struct</span><span style=
=3D"color:#000"> empty
                </span><span style=3D"color:#660">{};</span><span style=3D"=
color:#000"><br>
                  <br>
                </span><span style=3D"color:#008">struct</span><span style=
=3D"color:#000"> s1<br>
                </span><span style=3D"color:#660">{</span><span style=3D"co=
lor:#000"><br>
                  =C2=A0 no_identity n1</span><span style=3D"color:#660">;<=
/span><span style=3D"color:#000"> </span><span style=3D"color:#800">//State=
less
                  by default</span><span style=3D"color:#000"><br>
                  =C2=A0 stateless empty e1</span><span style=3D"color:#660=
">;</span><span style=3D"color:#000"> </span><span style=3D"color:#800">//E=
xplicitly
                  stateless.</span><span style=3D"color:#000"><br>
                  =C2=A0 no_identity n2</span><span style=3D"color:#660">;<=
/span><span style=3D"color:#000"> </span><span style=3D"color:#800">//OK,
                  n1 and n2 are aliases of the same object.</span><span sty=
le=3D"color:#000"><br>
                  =C2=A0 stateless empty e2</span><span style=3D"color:#660=
">;</span><span style=3D"color:#000"> </span><span style=3D"color:#800">//i=
l-formed.
                  `empty` was not declared `stateless`, and therefore it
                  must have identity.</span><span style=3D"color:#000"><br>
                </span><span style=3D"color:#660">};</span></div>
            </code></div>
          <br>
        </div>
      </div>
    </blockquote>
    I&#39;ve been thinking along these lines too.=C2=A0 The questions I hav=
e are:<br>
    * What if no_identify has a non-trivial constructor or destructor.=C2=
=A0
    When are they invoked in the example above and how many times?=C2=A0</d=
iv></blockquote><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin=
-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div bgcolor=
=3D"#FFFFFF" text=3D"#000000">
    * What is the lifetime of the object aliased by n1 and n2 above?=C2=A0
    (Essentially the same question).<br></div></blockquote><div><br>Well, i=
f there truly is only one `no_identity` subobject in `s1`, then by definiti=
on there must be only one constructor and destructor call. Any other compil=
er-generated per-subobject functions (copy/move assignment, etc) must simil=
arly find only one subobject.<br><br>Then again, if the type is truly `stat=
eless` and therefore has no identity, there would be nothing wrong on an im=
plementation level with declaring that the per-subobject functions get call=
ed once per member. But that plays havoc with C++&#39;s object rules, since=
 you would be calling a constructor multiple times on an object who&#39;s l=
ifetime has started. Or a destructor multiple times on the same object.<br>=
<br>Then again, we can change the lifetime rules of stateless types (since =
they&#39;re explicitly denoted as such) to be different. That calling a con=
structor on the same stateless object does not restart its lifetime or call=
ing the destructor multiple times does not end it. Or something like that.<=
br><br>It&#39;s certainly something to consider.<br></div></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/459db2af-7010-4247-9ec0-8dc26261c8b9%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/459db2af-7010-4247-9ec0-8dc26261c8b9=
%40isocpp.org</a>.<br />

------=_Part_1540_1747713128.1468532700326--

------=_Part_1539_2133550709.1468532700326--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Thu, 14 Jul 2016 15:28:47 -0700 (PDT)
Raw View
------=_Part_1081_182653929.1468535328079
Content-Type: multipart/alternative;
 boundary="----=_Part_1082_1324061900.1468535328080"

------=_Part_1082_1324061900.1468535328080
Content-Type: text/plain; charset=UTF-8

On Thursday, July 14, 2016 at 5:45:00 PM UTC-4, Nicol Bolas wrote:
>
> On Thursday, July 14, 2016 at 5:14:03 PM UTC-4, Tom Honermann wrote:
>>
>> On 7/14/2016 4:09 PM, Nicol Bolas wrote:
>>
>>
>> For example:
>>
>> stateless struct no_identity {};
>> struct empty {};
>>
>> struct s1
>> {
>>   no_identity n1; //Stateless by default
>>   stateless empty e1; //Explicitly stateless.
>>   no_identity n2; //OK, n1 and n2 are aliases of the same object.
>>   stateless empty e2; //il-formed. `empty` was not declared `stateless`,
>> and therefore it must have identity.
>> };
>>
>> I've been thinking along these lines too.  The questions I have are:
>> * What if no_identify has a non-trivial constructor or destructor.  When
>> are they invoked in the example above and how many times?
>>
> * What is the lifetime of the object aliased by n1 and n2 above?
>> (Essentially the same question).
>>
>
> Well, if there truly is only one `no_identity` subobject in `s1`, then by
> definition there must be only one constructor and destructor call. Any
> other compiler-generated per-subobject functions (copy/move assignment,
> etc) must similarly find only one subobject.
>
> Then again, if the type is truly `stateless` and therefore has no
> identity, there would be nothing wrong on an implementation level with
> declaring that the per-subobject functions get called once per member. But
> that plays havoc with C++'s object rules, since you would be calling a
> constructor multiple times on an object who's lifetime has started. Or a
> destructor multiple times on the same object.
>
> Then again, we can change the lifetime rules of stateless types (since
> they're explicitly denoted as such) to be different. That calling a
> constructor on the same stateless object does not restart its lifetime or
> calling the destructor multiple times does not end it. Or something like
> that.
>
> It's certainly something to consider.
>

After thinking about it some more, I don't think that it's such a big
problem. We should do the obvious.

Stateless subobjects, as a concept, relies on the idea that multiple
objects can exist in the same memory location. As such, having two of them
be the same type in the same location is *fine*. Well, it's fine from the
point of view of the standard. I think. That is, if we can make the
standard work for multiple objects of different types, we can make it work
for multiple objects of the *same* type.

So instead of looking at it as having two aliases for the same subobject,
you have two subobjects. But because they are stateless, they just so
happen to live in the same location. So they look identical. And
technically, you can't tell which one you're talking to. But that's OK
because they are *stateless* and therefore lack identity.

So yes, you call constructors and destructors once for each subobject
declaration. And other such operations. That's fine.

And I think so long as we restrict identity-lessness to types which are
declared stateless, we should avoid any user pitfalls.

--
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/98e8aa8d-6a70-4d8d-8803-c708720f01c9%40isocpp.org.

------=_Part_1082_1324061900.1468535328080
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Thursday, July 14, 2016 at 5:45:00 PM UTC-4, Nicol Bola=
s wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0=
..8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">On Th=
ursday, July 14, 2016 at 5:14:03 PM UTC-4, Tom Honermann wrote:<blockquote =
class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #=
ccc solid;padding-left:1ex">
 =20
   =20
 =20
  <div>
    <div>On 7/14/2016 4:09 PM, Nicol Bolas
      wrote:<br>
    </div>
    <blockquote type=3D"cite">
      <div dir=3D"ltr"><br>
        <div>For example:<br>
          <br>
          <div style=3D"background-color:rgb(250,250,250);border-color:rgb(=
187,187,187);border-style:solid;border-width:1px;word-wrap:break-word"><cod=
e>
              <div><span style=3D"color:#000">stateless </span><span style=
=3D"color:#008">struct</span><span style=3D"color:#000">
                  no_identity </span><span style=3D"color:#660">{};</span><=
span style=3D"color:#000"><br>
                </span><span style=3D"color:#008">struct</span><span style=
=3D"color:#000"> empty
                </span><span style=3D"color:#660">{};</span><span style=3D"=
color:#000"><br>
                  <br>
                </span><span style=3D"color:#008">struct</span><span style=
=3D"color:#000"> s1<br>
                </span><span style=3D"color:#660">{</span><span style=3D"co=
lor:#000"><br>
                  =C2=A0 no_identity n1</span><span style=3D"color:#660">;<=
/span><span style=3D"color:#000"> </span><span style=3D"color:#800">//State=
less
                  by default</span><span style=3D"color:#000"><br>
                  =C2=A0 stateless empty e1</span><span style=3D"color:#660=
">;</span><span style=3D"color:#000"> </span><span style=3D"color:#800">//E=
xplicitly
                  stateless.</span><span style=3D"color:#000"><br>
                  =C2=A0 no_identity n2</span><span style=3D"color:#660">;<=
/span><span style=3D"color:#000"> </span><span style=3D"color:#800">//OK,
                  n1 and n2 are aliases of the same object.</span><span sty=
le=3D"color:#000"><br>
                  =C2=A0 stateless empty e2</span><span style=3D"color:#660=
">;</span><span style=3D"color:#000"> </span><span style=3D"color:#800">//i=
l-formed.
                  `empty` was not declared `stateless`, and therefore it
                  must have identity.</span><span style=3D"color:#000"><br>
                </span><span style=3D"color:#660">};</span></div>
            </code></div>
          <br>
        </div>
      </div>
    </blockquote>
    I&#39;ve been thinking along these lines too.=C2=A0 The questions I hav=
e are:<br>
    * What if no_identify has a non-trivial constructor or destructor.=C2=
=A0
    When are they invoked in the example above and how many times?=C2=A0</d=
iv></blockquote><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-=
left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div bgcolor=3D"#FF=
FFFF" text=3D"#000000">
    * What is the lifetime of the object aliased by n1 and n2 above?=C2=A0
    (Essentially the same question).<br></div></blockquote><div><br>Well, i=
f there truly is only one `no_identity` subobject in `s1`, then by definiti=
on there must be only one constructor and destructor call. Any other compil=
er-generated per-subobject functions (copy/move assignment, etc) must simil=
arly find only one subobject.<br><br>Then again, if the type is truly `stat=
eless` and therefore has no identity, there would be nothing wrong on an im=
plementation level with declaring that the per-subobject functions get call=
ed once per member. But that plays havoc with C++&#39;s object rules, since=
 you would be calling a constructor multiple times on an object who&#39;s l=
ifetime has started. Or a destructor multiple times on the same object.<br>=
<br>Then again, we can change the lifetime rules of stateless types (since =
they&#39;re explicitly denoted as such) to be different. That calling a con=
structor on the same stateless object does not restart its lifetime or call=
ing the destructor multiple times does not end it. Or something like that.<=
br><br>It&#39;s certainly something to consider.<br></div></div></blockquot=
e><div><br>After thinking about it some more, I don&#39;t think that it&#39=
;s such a big problem. We should do the obvious.<br><br>Stateless subobject=
s, as a concept, relies on the idea that multiple objects can exist in the =
same memory location. As such, having two of them be the same type in the s=
ame location is <i>fine</i>. Well, it&#39;s fine from the point of view of =
the standard. I think. That is, if we can make the standard work for multip=
le objects of different types, we can make it work for multiple objects of =
the <i>same</i> type.<br><br>So instead of looking at it as having two alia=
ses for the same subobject, you have two subobjects. But because they are s=
tateless, they just so happen to live in the same location. So they look id=
entical. And technically, you can&#39;t tell which one you&#39;re talking t=
o. But that&#39;s OK because they are <i>stateless</i> and therefore lack i=
dentity.<br><br>So yes, you call constructors and destructors once for each=
 subobject declaration. And other such operations. That&#39;s fine.<br><br>=
And I think so long as we restrict identity-lessness to types which are dec=
lared stateless, we should avoid any user pitfalls.<br></div></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/98e8aa8d-6a70-4d8d-8803-c708720f01c9%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/98e8aa8d-6a70-4d8d-8803-c708720f01c9=
%40isocpp.org</a>.<br />

------=_Part_1082_1324061900.1468535328080--

------=_Part_1081_182653929.1468535328079--

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Thu, 14 Jul 2016 16:23:49 -0700
Raw View
On quinta-feira, 14 de julho de 2016 13:09:36 PDT Nicol Bolas wrote:
> > Why can't std::allocator be declared in C++2x as stateless?
>
> Because that would potentially break code. The size of any object that used
> `allocator` as a member variable would change, thus breaking any ABIs
> involving such objects.

How? If we require both in the declaration of the class and where it's used,
then no current code would be affected.

If the declaration doesn't use stateless:
 object occupies space, regardless of declaration
If the declaration specifies stateless or stateless(true)
 if class specifies stateless:
  object occupies no space
 if class doesn't specify stateless:
  ill-formed
If the declaration specifies stateless(auto)
 if class specifies stateless:
  object occupies no space
 if class doesn't specify stateless:
  object occupies space

In a green field, we'd have stateless only on the class declaration. We're not
in a green field.

> > They probably should, but we have two options:
> >
> > 1) require "fake stateless" classes to have a member
> > 2) require stateless classes to have a "stateless" keywords
> >
> > Why not #2?
>
> I do appreciate the simplicity of #2. It was after all my original design
> from the very first version of this idea
> <https://groups.google.com/a/isocpp.org/forum/#!searchin/std-proposals/state
> less$20inner/std-proposals/HjGujSdKXX0/27WIWTc_EwAJ>. However, remember back
> to the defining problem for this proposal. Someone gives us a type. We want
> to use that type as a member variable. But if that type is empty, we don't
> want our type taking up extra space.

But only if the class author declares that it shouldn't take up space. If the
class author requires that the object have a unique pointer address, different
from any and all other objects, then you cannot ignore her.

> #2 is not a solution to this problem. Why? Because people will still pass
> us empty-but-not-stateless types. And therefore this:
>
> template<typename Alloc>
> struct DataBlock : public Alloc
> {};
>
> Will always be a better alternative than this:
>
> template<typename Alloc>
> struct DataBlock
> {
>   Alloc a;
> };
>
> In the former, we are guaranteed to avoid bloat for any empty class. In the
> latter, we only avoid bloat if the user provides a stateless type. And
> stateless types will *always* be a subset of empty types.

But you don't know if you're allowed to "avoid bloat". Maybe your (premature)
optimisation will break code later.

I really think that the class author should be allowed to decide whether the
use of that class can take up no space.

> For example:
>
> stateless struct no_identity {};
> struct empty {};
>
> struct s1
> {
>   no_identity n1; //Stateless by default
>   stateless empty e1; //Explicitly stateless.
>   no_identity n2; //OK, n1 and n2 are aliases of the same object.
>   stateless empty e2; //il-formed. `empty` was not declared `stateless`,
> and therefore it must have identity.
> };

That's the green-field case. It's the cleanest solution, I agree, but that
doesn't allow us to use it for std::allocator.

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--
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/8662886.rkv0mXdmeW%40tjmaciei-mobl1.

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Thu, 14 Jul 2016 16:29:57 -0700
Raw View
On quinta-feira, 14 de julho de 2016 17:13:57 PDT Tom Honermann wrote:
> On 7/14/2016 4:09 PM, Nicol Bolas wrote:
> > For example:
> >
> >
> > stateless structno_identity {};
> > structempty {};
> >
> > structs1
> > {
> >
> >   no_identity n1;//Stateless by default
> >   stateless empty e1;//Explicitly stateless.
> >   no_identity n2;//OK, n1 and n2 are aliases of the same object.
> >   stateless empty e2;//il-formed. `empty` was not declared
> >
> > `stateless`, and therefore it must have identity.
> > };
>
> I've been thinking along these lines too.  The questions I have are:
> * What if no_identify has a non-trivial constructor or destructor. When
> are they invoked in the example above and how many times?
> * What is the lifetime of the object aliased by n1 and n2 above?
> (Essentially the same question).

Interesting questions.

My first reaction is to say that a stateless class must only have static data
members and static member functions. Therefore, it would not be allowed to
declare a constructor or destructor.

For std::allocator to be made stateless, the implementation would need to
change all of the member functions to be static. This could lead to a binary
compatibility problem (MSVC encodes the "staticness" of a member function in
the mangled name). That can be solved by saying all members functions in a
stateless class are implicitly static and therefore cannot use the this
pointer.

As a consequence of either solution, you can't add a constructor or a
destructor to a stateless class.

But maybe we can: a default constructor and a destructor are actually
possible. They'd be called (without a this pointer) whenever the object begins
or ends its lifetime. That is:

 {
  no_identity n1;
  f();
  no_identity n2;
  g();
 }

would be equivalent to:

 {
  no_identity::no_identity();
  f();
  no_identity::no_identity();
  g();
  no_identity::~no_identity();
  no_identity::~no_identity();
 }

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--
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/12626556.8ovVoMRHXD%40tjmaciei-mobl1.

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Thu, 14 Jul 2016 16:33:54 -0700
Raw View
On quinta-feira, 14 de julho de 2016 13:27:54 PDT Arthur O'Dwyer wrote:
> On another angle of the topic, it occurred to me the other day that if a=
=20
> programmer is trying to express the idea of "This object has no address =
=E2=80=94=20
> that is, I promise not to take its address except perhaps implicitly in=
=20
> trivial ways" =E2=80=94 the most natural way to express that is with the =
newly=20
> freed-up register storage class.

Indeed it is. But it would be quite a head-scratcher to read code like:

 register class allocator
 {
  ...
 };

 struct my_data
 {
  register allocator alloc;
 };

It's one of those things we could do for the sake of convenience, but twent=
y=20
years from now we'd be asking ourselves "why register"?

--=20
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--=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/2125973.PujvrRexYn%40tjmaciei-mobl1.

.


Author: Bjorn Reese <breese@mail1.stofanet.dk>
Date: Sat, 16 Jul 2016 12:55:31 +0200
Raw View
Can the stateless subobjects access the member variables of the parent
class?

--
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/578A12A3.5060201%40mail1.stofanet.dk.

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Sat, 16 Jul 2016 09:26:43 -0700
Raw View
On s=C3=A1bado, 16 de julho de 2016 12:55:31 PDT Bjorn Reese wrote:
> Can the stateless subobjects access the member variables of the parent
> class?

I don't see how.

--=20
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center

--=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/2179076.PThPMozros%40tjmaciei-mobl1.

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sat, 16 Jul 2016 10:33:40 -0700 (PDT)
Raw View
------=_Part_485_486861372.1468690420107
Content-Type: multipart/alternative;
 boundary="----=_Part_486_1135725609.1468690420107"

------=_Part_486_1135725609.1468690420107
Content-Type: text/plain; charset=UTF-8

On Thursday, July 14, 2016 at 7:23:53 PM UTC-4, Thiago Macieira wrote:
>
> On quinta-feira, 14 de julho de 2016 13:09:36 PDT Nicol Bolas wrote:
> > > Why can't std::allocator be declared in C++2x as stateless?
> >
> > Because that would potentially break code. The size of any object that
> used
> > `allocator` as a member variable would change, thus breaking any ABIs
> > involving such objects.
>
> How? If we require both in the declaration of the class and where it's
> used,
> then no current code would be affected.
>

This now requires that everyone go through their code and annotate all of
their empty types with `stateless`. Not to mention going through the
standard library and deciding which classes that are currently "empty"
should be explicitly declared `stateless`. Not to mention cases where the
library is fixed and cannot be upgraded. Not to mention ABI issues and so
forth.

If you force this double-stateless declaration, then people will simply not
care. They'll go right back to deriving from empty classes to avoid bloat.
Why? Because *it always works*, whereas the `stateless` version does not.
If stateless subobjects are going to solve this problem, then the feature
*must* be able to work on the exact same types that EBO can work on right
now.

By the nature of the problem statement, this is non-negotiable.

> > They probably should, but we have two options:
> > >
> > > 1) require "fake stateless" classes to have a member
> > > 2) require stateless classes to have a "stateless" keywords
> > >
> > > Why not #2?
> >
> > I do appreciate the simplicity of #2. It was after all my original
> design
> > from the very first version of this idea
> > <
> https://groups.google.com/a/isocpp.org/forum/#!searchin/std-proposals/state
> > less$20inner/std-proposals/HjGujSdKXX0/27WIWTc_EwAJ>. However, remember
> back
> > to the defining problem for this proposal. Someone gives us a type. We
> want
> > to use that type as a member variable. But if that type is empty, we
> don't
> > want our type taking up extra space.
>
> But only if the class author declares that it shouldn't take up space. If
> the
> class author requires that the object have a unique pointer address,
> different
> from any and all other objects, then you cannot ignore her.
>

But there's no way to explicitly state that as it currently stands. So you
can either:

A) Assume that every empty class currently existing requires each instance
to have a pointer address that is different from every other instance.

B) Assume that every empty class currently existing does not require unique
identity for its instances.

Furthermore, I don't believe that option A means that you *must* forbid
such classes from being used statelessly. All you need to do is make sure
they don't overlap. Just like with standard layout rules.


> > #2 is not a solution to this problem. Why? Because people will still
> pass
> > us empty-but-not-stateless types. And therefore this:
> >
> > template<typename Alloc>
> > struct DataBlock : public Alloc
> > {};
> >
> > Will always be a better alternative than this:
> >
> > template<typename Alloc>
> > struct DataBlock
> > {
> >   Alloc a;
> > };
> >
> > In the former, we are guaranteed to avoid bloat for any empty class. In
> the
> > latter, we only avoid bloat if the user provides a stateless type. And
> > stateless types will *always* be a subset of empty types.
>
> But you don't know if you're allowed to "avoid bloat". Maybe your
> (premature)
> optimisation will break code later.
>

No. That code *will never break*.

In current C++ rules, `Alloc` *cannot assume* that its pointer value is
unique among all other objects. Why? Because the first NSDM of an object
often has the same pointer address as the containing object. Because base
classes often have the same address as their derived class. In fact, this
is the whole basis of the EBO rule: that the base class and derived class
can have the same address. Unique identity of an object does not mean
unique address among all object types. Nor does it mean having a region of
storage that is disjoint from all other objects (indeed, being a subobject
at all makes that impossible).

What `Alloc` *can assume* right now is that if two pointers of type `Alloc`
are equal, then they are pointing to the same object instance. And if they
are unequal, then they are pointing to separate instances. And that is
where statelessness has a problem, since you can use such a unique pointer
to create and access per-instance state.

But it *only* has a problem if there are *two* (or more) stateless
subobjects of type `Alloc` within the same class (well, the scope of the
problem is a bit more complex, but it's all within the same object). After
all, pointers to stateless subobjects must refer to a valid memory address
within the object that contains them (just like any subobject). So if you
have two distinct instances of `DataBlock<Alloc>`, each instance will have
a *different address* for its `a` member.

So there is no problem with `DataBlock`'s usage of a stateless `Alloc`.
Member functions of `Alloc` can assume that there is a 1:1 correspondence
between its address and the address of any (valid) pointer to an `Alloc`.

I really think that the class author should be allowed to decide whether
> the
> use of that class can take up no space.
>

Given the limitations of identity as outlined before (ie: one subobject of
that type per containing object, recursively), give me a circumstance where
the implementation of an empty type would break under the stateless rules
as I have outlined them. And this "something" must be legal, well-defined
C++.


> > For example:
> >
> > stateless struct no_identity {};
> > struct empty {};
> >
> > struct s1
> > {
> >   no_identity n1; //Stateless by default
> >   stateless empty e1; //Explicitly stateless.
> >   no_identity n2; //OK, n1 and n2 are aliases of the same object.
> >   stateless empty e2; //il-formed. `empty` was not declared `stateless`,
> > and therefore it must have identity.
> > };
>
> That's the green-field case. It's the cleanest solution, I agree, but that
> doesn't allow us to use it for std::allocator.
>

Why not? `no_identity` made it perfectly clear that two subobjects could
have the same address. That's what it means to declare them `stateless`.
However, since `empty` was not declared `stateless`, that means that it
cannot have two subobjects that have the same address.

`std::allocator` would not need to be declared `stateless` in order to be
used as a single, stateless NSDM.

--
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/c4c112ee-ccea-43b0-9ae2-1baa20f04944%40isocpp.org.

------=_Part_486_1135725609.1468690420107
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Thursday, July 14, 2016 at 7:23:53 PM UTC-4, Thiago Mac=
ieira wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-lef=
t: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On quinta-feira, 1=
4 de julho de 2016 13:09:36 PDT Nicol Bolas wrote:
<br>&gt; &gt; Why can&#39;t std::allocator be declared in C++2x as stateles=
s?
<br>&gt;=20
<br>&gt; Because that would potentially break code. The size of any object =
that used
<br>&gt; `allocator` as a member variable would change, thus breaking any A=
BIs
<br>&gt; involving such objects.
<br>
<br>How? If we require both in the declaration of the class and where it&#3=
9;s used,=20
<br>then no current code would be affected.
<br></blockquote><div><br>This now requires that everyone go through their =
code and annotate all of their empty types with `stateless`. Not to mention=
 going through the standard library and deciding which classes that are cur=
rently &quot;empty&quot; should be explicitly declared `stateless`. Not to =
mention cases where the library is fixed and cannot be upgraded. Not to men=
tion ABI issues and so forth.<br><br>If you force this double-stateless dec=
laration, then people will simply not care. They&#39;ll go right back to de=
riving from empty classes to avoid bloat. Why? Because <i>it always works</=
i>, whereas the `stateless` version does not. If stateless subobjects are g=
oing to solve this problem, then the feature <i>must</i> be able to work on=
 the exact same types that EBO can work on right now.<br><br>By the nature =
of the problem statement, this is non-negotiable.<br><br></div><blockquote =
class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1p=
x #ccc solid;padding-left: 1ex;">
&gt; &gt; They probably should, but we have two options:
<br>&gt; &gt;=20
<br>&gt; &gt; 1) require &quot;fake stateless&quot; classes to have a membe=
r
<br>&gt; &gt; 2) require stateless classes to have a &quot;stateless&quot; =
keywords
<br>&gt; &gt;=20
<br>&gt; &gt; Why not #2?
<br>&gt;=20
<br>&gt; I do appreciate the simplicity of #2. It was after all my original=
 design
<br>&gt; from the very first version of this idea
<br>&gt; &lt;<a href=3D"https://groups.google.com/a/isocpp.org/forum/#!sear=
chin/std-proposals/state" target=3D"_blank" rel=3D"nofollow" onmousedown=3D=
"this.href=3D&#39;https://groups.google.com/a/isocpp.org/forum/#!searchin/s=
td-proposals/state&#39;;return true;" onclick=3D"this.href=3D&#39;https://g=
roups.google.com/a/isocpp.org/forum/#!searchin/std-proposals/state&#39;;ret=
urn true;">https://groups.google.com/a/<wbr>isocpp.org/forum/#!searchin/<wb=
r>std-proposals/state</a>
<br>&gt; less$20inner/std-proposals/<wbr>HjGujSdKXX0/27WIWTc_EwAJ&gt;. Howe=
ver, remember back
<br>&gt; to the defining problem for this proposal. Someone gives us a type=
.. We want
<br>&gt; to use that type as a member variable. But if that type is empty, =
we don&#39;t
<br>&gt; want our type taking up extra space.
<br>
<br>But only if the class author declares that it shouldn&#39;t take up spa=
ce. If the=20
<br>class author requires that the object have a unique pointer address, di=
fferent=20
<br>from any and all other objects, then you cannot ignore her.
<br></blockquote><div><br>But there&#39;s no way to explicitly state that a=
s it currently stands. So you can either:<br><br>A) Assume that every empty=
 class currently existing requires each instance to have a pointer address =
that is different from every other instance.<br><br>B) Assume that every em=
pty class currently existing does not require unique identity for its insta=
nces.<br><br>Furthermore, I don&#39;t believe that option A means that you =
<i>must</i> forbid such classes from being used statelessly. All you need t=
o do is make sure they don&#39;t overlap. Just like with standard layout ru=
les.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;marg=
in-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<br>&gt; #2 is not a solution to this problem. Why? Because people will sti=
ll pass
<br>&gt; us empty-but-not-stateless types. And therefore this:
<br>&gt;=20
<br>&gt; template&lt;typename Alloc&gt;
<br>&gt; struct DataBlock : public Alloc
<br>&gt; {};
<br>&gt;=20
<br>&gt; Will always be a better alternative than this:
<br>&gt;=20
<br>&gt; template&lt;typename Alloc&gt;
<br>&gt; struct DataBlock
<br>&gt; {
<br>&gt; =C2=A0 Alloc a;
<br>&gt; };
<br>&gt;=20
<br>&gt; In the former, we are guaranteed to avoid bloat for any empty clas=
s. In the
<br>&gt; latter, we only avoid bloat if the user provides a stateless type.=
 And
<br>&gt; stateless types will *always* be a subset of empty types.
<br>
<br>But you don&#39;t know if you&#39;re allowed to &quot;avoid bloat&quot;=
.. Maybe your (premature)=20
<br>optimisation will break code later.<br></blockquote><div><br>No. That c=
ode <i>will never break</i>.<br><br>In current C++ rules, `Alloc` <i>cannot=
 assume</i> that its pointer value is unique among all other objects. Why? =
Because the first NSDM of an object often has the same pointer address as t=
he containing object. Because base classes often have the same address as t=
heir derived class. In fact, this is the whole basis of the EBO rule: that =
the base class and derived class can have the same address. Unique identity=
 of an object does not mean unique address among all object types. Nor does=
 it mean having a region of storage that is disjoint from all other objects=
 (indeed, being a subobject at all makes that impossible).<br><br>What `All=
oc` <i>can assume</i> right now is that if two pointers of type `Alloc` are=
 equal, then they are pointing to the same object instance. And if they are=
 unequal, then they are pointing to separate instances. And that is where s=
tatelessness has a problem, since you can use such a unique pointer to crea=
te and access per-instance state.<br><br>But it <i>only</i> has a problem i=
f there are <i>two</i> (or more) stateless subobjects of type `Alloc` withi=
n the same class (well, the scope of the problem is a bit more complex, but=
 it&#39;s all within the same object). After all, pointers to stateless sub=
objects must refer to a valid memory address within the object that contain=
s them (just like any subobject). So if you have two distinct instances of =
`DataBlock&lt;Alloc&gt;`, each instance will have a <i>different address</i=
> for its `a` member.<br><br>So there is no problem with `DataBlock`&#39;s =
usage of a stateless `Alloc`. Member functions of `Alloc` can assume that t=
here is a 1:1 correspondence between its address and the address of any (va=
lid) pointer to an `Alloc`.<br><br></div><blockquote class=3D"gmail_quote" =
style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-l=
eft: 1ex;">
I really think that the class author should be allowed to decide whether th=
e=20
<br>use of that class can take up no space.<br></blockquote><div><br>Given =
the limitations of identity as outlined before (ie: one subobject of that t=
ype per containing object, recursively), give me a circumstance where the i=
mplementation of an empty type would break under the stateless rules as I h=
ave outlined them. And this &quot;something&quot; must be legal, well-defin=
ed C++.<br>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin: 0=
;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">&gt; Fo=
r example:
<br>&gt;=20
<br>&gt; stateless struct no_identity {};
<br>&gt; struct empty {};
<br>&gt;=20
<br>&gt; struct s1
<br>&gt; {
<br>&gt; =C2=A0 no_identity n1; //Stateless by default
<br>&gt; =C2=A0 stateless empty e1; //Explicitly stateless.
<br>&gt; =C2=A0 no_identity n2; //OK, n1 and n2 are aliases of the same obj=
ect.
<br>&gt; =C2=A0 stateless empty e2; //il-formed. `empty` was not declared `=
stateless`,
<br>&gt; and therefore it must have identity.
<br>&gt; };
<br>
<br>That&#39;s the green-field case. It&#39;s the cleanest solution, I agre=
e, but that=20
<br>doesn&#39;t allow us to use it for std::allocator.<br></blockquote><div=
><br>Why not? `no_identity` made it perfectly clear that two subobjects cou=
ld have the same address. That&#39;s what it means to declare them `statele=
ss`. However, since `empty` was not declared `stateless`, that means that i=
t cannot have two subobjects that have the same address.<br><br>`std::alloc=
ator` would not need to be declared `stateless` in order to be used as a si=
ngle, stateless NSDM.<br></div></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/c4c112ee-ccea-43b0-9ae2-1baa20f04944%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/c4c112ee-ccea-43b0-9ae2-1baa20f04944=
%40isocpp.org</a>.<br />

------=_Part_486_1135725609.1468690420107--

------=_Part_485_486861372.1468690420107--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sat, 16 Jul 2016 11:09:45 -0700 (PDT)
Raw View
------=_Part_1162_2093239738.1468692585857
Content-Type: multipart/alternative;
 boundary="----=_Part_1163_1676809549.1468692585857"

------=_Part_1163_1676809549.1468692585857
Content-Type: text/plain; charset=UTF-8

Here's the next revision of the proposal.

I've added an issues section that discusses the identity problem that we've
discussed here, along with an exploration of possible solutions. None of
those are integrated into the actual proposed design yet, which remains as
it was before.

I'm really leaning towards the solution, where we forbid any stateless
subobjects that violate unique identity, but allowing classes explicitly
declared stateless to lack unique identity. In such cases, multiple objects
of the same type would coexist in the same storage. So you'd get multiple
constructors and destructors called on the same memory location. But since
you stated explicitly that the type was `stateless`, then you should know
better than to use the `this` pointer in a way that expects unique identity.

--
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/b8c11720-17cc-4953-b47a-c37f490ae4c9%40isocpp.org.

------=_Part_1163_1676809549.1468692585857
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Here&#39;s the next revision of the proposal.<br><br>I&#39=
;ve added an issues section that discusses the identity problem that we&#39=
;ve discussed here, along with an exploration of possible solutions. None o=
f those are integrated into the actual proposed design yet, which remains a=
s it was before.<br><br>I&#39;m really leaning towards the solution, where =
we forbid any stateless subobjects that violate unique identity, but allowi=
ng classes explicitly declared stateless to lack unique identity. In such c=
ases, multiple objects of the same type would coexist in the same storage. =
So you&#39;d get multiple constructors and destructors called on the same m=
emory location. But since you stated explicitly that the type was `stateles=
s`, then you should know better than to use the `this` pointer in a way tha=
t expects unique identity.<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/b8c11720-17cc-4953-b47a-c37f490ae4c9%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/b8c11720-17cc-4953-b47a-c37f490ae4c9=
%40isocpp.org</a>.<br />

------=_Part_1163_1676809549.1468692585857--

------=_Part_1162_2093239738.1468692585857
Content-Type: text/html; charset=UTF-8; name="Stateless Subobjects.html"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename="Stateless Subobjects.html"
X-Attachment-Id: 427eaf74-d623-40f7-9faa-bb1a28b4bfb4
Content-ID: <427eaf74-d623-40f7-9faa-bb1a28b4bfb4>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.=
w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns=3D"http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8" =
/>
  <meta http-equiv=3D"Content-Style-Type" content=3D"text/css" />
  <meta name=3D"generator" content=3D"pandoc" />
  <meta name=3D"date" content=3D"2016-07-13" />
  <title>Stateless Subobjects and Types, pre-release v3</title>
  <style type=3D"text/css">code{white-space: pre;}</style>
</head>
<body>
<div id=3D"header">
<h1 class=3D"title">Stateless Subobjects and Types, pre-release v3</h1>
<h3 class=3D"date">July 13, 2016</h3>
</div>
<div id=3D"TOC">
<ul>
<li><a href=3D"#motivation">Motivation and Scope</a></li>
<li><a href=3D"#design">Design</a><ul>
<li><a href=3D"#implementation-and-restrictions">Implementation and Restric=
tions</a></li>
</ul></li>
<li><a href=3D"#potential-issues">Potential issues</a><ul>
<li><a href=3D"#identity">Empty object identity</a></li>
<li><a href=3D"#the-unknown">The Unknown</a></li>
</ul></li>
<li><a href=3D"#alternative-designs-explored">Alternative Designs Explored<=
/a><ul>
<li><a href=3D"#magic-standard-library-wrapper-type">Magic standard library=
 wrapper type</a></li>
<li><a href=3D"#stateless-by-type-declaration">Stateless by type declaratio=
n</a></li>
</ul></li>
<li><a href=3D"#changelist">Changelist</a><ul>
<li><a href=3D"#from-pre-release-v2">From pre-release v2:</a></li>
<li><a href=3D"#from-pre-release-v1">From pre-release v1:</a></li>
</ul></li>
<li><a href=3D"#acknowledgments">Acknowledgments</a></li>
</ul>
</div>
<p>This proposal specifies the ability to declare member and base class sub=
objects which do not take up space in the objects they are contained within=
.. It also allows the user to define classes which will always be used in su=
ch a fashion.</p>
<h1 id=3D"motivation">Motivation and Scope</h1>
<p>An object is stateless, conceptually speaking, if it has no non-static d=
ata members. As such, the state of any particular instance is no different =
from another. Because of this, there is no conceptual reason why a stateles=
s object needs to have a region of storage associated with it.</p>
<p>In C++, a class would be stateless if it has no non-static data members =
(NSDMs) and all of its base classes likewise are stateless as well. <code>i=
s_empty_v</code> qualifies as a useful test, but technically other classes =
could qualify as well (those with virtual members/base classes).</p>
<p>There are many times when a user wants to use a class that the user prov=
ides, but the class may or may not be logically stateless. If it is statele=
ss, then it would be best if the class which uses it would not grow in size=
 simply due to the presence of the stateless subobject. After all, a concep=
tually stateless object does not need to take up space to do its job.</p>
<p>To avoid this, users will frequently use standard layout rules and the e=
mpty base optimization to allow them to have access to a stateless subobjec=
t:</p>
<pre><code>template&lt;typename Alloc&gt;
struct DataBlock : public Alloc
{
};</code></pre>
<p>In this case, if <code>Alloc</code> is empty, then so long as <code>Data=
Block</code> follows standard layout rules, the user is guaranteed that <co=
de>DataBlock</code> is no larger than it would have been if <code>Alloc</co=
de> were not empty. Even if it does not follow standard layout, the compile=
r is free to optimize the empty base <code>Alloc</code> away.</p>
<p>There are of course problems with such a use. If <code>Alloc</code> is n=
ot empty (and <code>DataBlock</code> does not require that it is), and <cod=
e>Alloc</code> declares a virtual function, it is possible that <code>DataB=
lock&lt;Alloc&gt;</code> will accidentally override that virtual function. =
Or not quite override it and cause a compile error. Whereas if <code>Alloc<=
/code> were a non-static data member, this could easily be avoided.</p>
<p>Equally importantly, this use of <code>Alloc</code> is simply not how a =
user would naturally write this class. Inheritance is supposed to model an =
&quot;is a&quot; relationship. Yet conceptually, <code>DataBlock</code> is =
not an <code>Alloc</code>; it <em>has</em> an <code>Alloc</code>. <code>Dat=
aBlock</code> uses inheritance, not to model a relationship, but as an opti=
mization tool, to keep the class from growing unnecessarily.</p>
<p>The intent of this proposal is to permit, among other things, classes li=
ke <code>DataBlock</code> to declare <code>Alloc</code> as a non-static dat=
a member. And if <code>Alloc</code> is empty, then <code>DataBlock</code> c=
an use syntax to make the <code>Alloc</code> NSDM take up no space in <code=
>DataBlock</code>'s layout.</p>
<p>This would also be recursive, so that if <code>Alloc</code> had no NSDMs=
, and <code>DataBlock&lt;Alloc&gt;</code> had no NSDMs besides the <code>Al=
loc</code> member, then <code>DataBlock&lt;Alloc&gt;</code> would also be c=
onsidered an empty type. And therefore, some other type could use it in a s=
tateless fashion.</p>
<h1 id=3D"design">Design</h1>
<p>We define two concepts: stateless subobjects and stateless classes. A st=
ateless class is really just shorthand for the former; it declares that ins=
tances of the class can only be created as stateless subobjects of some oth=
er type.</p>
<p>Note: The following syntax is entirely preliminary. This proposal is not=
 wedded to the idea of introducing a new keyword or somesuch. This syntax i=
s here simply for the sake of understanding how the functionality should ge=
nerally be specified. The eventual syntax could be a contextual keyword lik=
e <code>final</code> and <code>override</code>, or it could be something el=
se.</p>
<h3 id=3D"stateless-subobojects">Stateless subobojects</h3>
<p>A non-static data member subobject of a type can be declared stateless w=
ith the following syntax:</p>
<pre><code>struct Data
{
    stateless Type val;
};</code></pre>
<p>A base class subobject of a type can be declared stateless with the foll=
owing syntax:</p>
<pre><code>struct Data : public stateless Type
{
    ...
};</code></pre>
<p>In both cases, if <code>Type</code> is not an empty class, then this is =
a compile error. <code>stateless</code> cannot be applied to a base class w=
hich uses <code>virtual</code> inheritance.</p>
<p>Member subobjects that are arrayed cannot be declared with <code>statele=
ss</code> property. Variables which are not non-static data members cannot =
be declared with the stateless property.</p>
<p><code>stateless</code> cannot be applied to a member of a <code>union</c=
ode> class.</p>
<p>The stateless property can be conditional, based on a compile-time condi=
tion like <code>noexcept</code>. This is done as follows:</p>
<pre><code>template&lt;typename Alloc&gt;
struct DataBlock
{
    stateless(is_empty_v&lt;Alloc&gt;) Alloc a;
};</code></pre>
<p>In this case, <code>a</code> will be a stateless member only if its type=
 is empty. If the condition is false, then it is as if the stateless proper=
ty were not applied to the subobject.</p>
<p>To facilitate common use patterns, the <code>stateless(auto)</code> synt=
ax for subobjects shall be equivalent to <code>stateless(std::is_empty_v&lt=
;T&gt;)</code>, where <code>T</code> is the type of the subobject being dec=
lared.</p>
<h3 id=3D"stateless-behavior">Stateless behavior</h3>
<p>Stateless subobjects have no effect on the layout or size of their conta=
ining object. Similarly, the rules for standard layout types ignore the pre=
sence of any stateless subobjects. And thus, two classes can be layout comp=
atible even if they differ by the presence of stateless subobjects.</p>
<p>Stateless subobjects otherwise have the same effects on their containing=
 types as regular subobjects do. For example, a stateless subobject can cau=
se its container to not be trivially copyable, if it has a non-trivial copy=
 constructor (even though the object by definition has no state to copy).</=
p>
<p>The definition of &quot;empty class&quot; (per <code>std::is_empty</code=
>) must now be expanded. The rules for an empty class are:</p>
<ul>
<li>Non-union class.</li>
<li>No virtual functions.</li>
<li>No virtual base classes.</li>
<li>No non-empty base classes.</li>
<li>No non-stateless NSDMs.</li>
</ul>
<p>In all other ways, except where detailed below, a stateless subobject wo=
rks identically to a non-stateless one. Stateless subobjects are initialize=
d and destroyed just as if they were not stateless. Stateless subobjects un=
dergo copy and move construction and assignment along with all other subobj=
ects (though they will likely not be doing much). In particular, stateless =
subobjects are still members/base classes of the types that contain them, s=
o aggregate initialization of members (and bases) will still have to take t=
hem into account:</p>
<pre><code>struct foo {};

struct aggregate
{
  stateless foo f;
  int b;
};

//It may have no state, but `f` must still be initialized.
aggregate agg =3D {{}, 4};</code></pre>
<p>Note that the alignment of a stateless subobject will still impact the a=
lignment of the containing class. A <code>stateless</code> member declarati=
on can include an <code>alignas</code> specifier as well.</p>
<h3 id=3D"stateless-types">Stateless types</h3>
<p>The stateless property can be applied to (non-union) types as well:</p>
<pre><code>stateless class ClassName : BaseClasses
{
    ...
};</code></pre>
<p>The <code>stateless</code> keyword must be consistently associated with =
any forward declarations for stateless types.</p>
<pre><code>class ClassName;  //Not a stateless type.

stateless class ClassName  //Compiler error: you told me it wasn&#39;t stat=
eless before.
{
};</code></pre>
<p>And vice-versa.</p>
<p>A stateless class definition is ill-formed if the class is not empty (pe=
r the expanded rules for empty classes).</p>
<p>The size of a stateless class is not modified by being stateless. Theref=
ore, the size of a stateless class shall be no different from the size of a=
ny other empty class.</p>
<p>The statelessness of a type can be conditional, just like subobjects:</p=
>
<pre><code>template&lt;typename T&gt;
stateless(is_empty_v&lt;T&gt;) struct Foo : public T {};</code></pre>
<p>Here, <code>Foo</code> may or may not be stateless, depending on whether=
 <code>T</code> is empty. If the constant expression evaluates to <code>fal=
se</code>, then the class is not stateless.</p>
<p>To make certain conditions easier, there will be the <code>stateless(aut=
o)</code> syntax. When applied to a class declaration, <code>stateless(auto=
)</code> will cause the class to be stateless if the class is empty. If the=
 class is not empty, then the class will not be stateless.</p>
<p>When a stateless class is used to create an object in a way that cannot =
have <code>stateless</code> applied to it, then the code behaves just as it=
 would if the class did not have the <code>stateless</code> keyword. Theref=
ore, you can heap allocate arrays of stateless classes, and they will funct=
ion just like any heap allocated array of empty classes. You can declare an=
 automatic variable of a stateless type, and it will behave as any empty cl=
ass (note: implementations may optimize such objects to take up no stack sp=
ace if possible, but they are not required to do so).</p>
<p>However, when a stateless class is used to declare a direct subobject of=
 another type, that subobject will be implicitly stateless. It is perfectly=
 valid to explicitly specify <code>stateless</code> on a member/base class =
of a stateless type as well. If the conditions on the two <code>stateless</=
code> properties do not agree (one resolves to true and the other false), t=
hen the program is il-formed.<a href=3D"#fn1" class=3D"footnoteRef" id=3D"f=
nref1"><sup>1</sup></a></p>
<p>Declaring an array of a stateless type as an NSDM is forbidden. Stateles=
s types may not be used as members of a union.</p>
<p>The standard library does not need to have a traits class to detect if a=
 type is stateless. A type with such a declaration can be used in any way t=
hat any type can, so <code>is_empty</code> is sufficient.</p>
<h3 id=3D"stateless-anonymous-types">Stateless anonymous types</h3>
<p>Statelessness can be applied to anonymous types as well:</p>
<pre><code>stateless(auto) struct
{
    Data d;
} varName;</code></pre>
<p>The <code>stateless</code> property applies to the struct declaration, n=
ot the variable. As such, <code>decltype(varName)</code> will be a stateles=
s type if <code>Data</code> is a stateless type. Such declarations can only=
 be made as non-static data members.</p>
<h2 id=3D"implementation-and-restrictions">Implementation and Restrictions<=
/h2>
<p>In a perfect world, the above would be the only restrictions on stateles=
s types. C++ of course is never perfect.</p>
<h3 id=3D"memory-locations">Memory locations</h3>
<p>In C++ as it currently stands, every object needs to have a memory locat=
ion. And two separate objects of unrelated types cannot have the <em>same</=
em> memory location.</p>
<p>Stateless subobojects effectively have to be able to break this rule. Th=
e memory location of a stateless subobject is more or less irrelevant. Sinc=
e the type is stateless, there is no independent state to access. So one in=
stance is functionally no different from another.<a href=3D"#fn2" class=3D"=
footnoteRef" id=3D"fnref2"><sup>2</sup></a></p>
<p>As such, the general idea is that a stateless subobject could have any a=
ddress within the storage of the object which contains it. This means that =
a stateless subobject can have the same address as any other subobject in i=
ts containing object's type.</p>
<p>This is not really an implementation problem, since stateless suboboject=
s by their very nature have no state to access. As such, the specific addre=
ss of their <code>this</code> pointer is irrelevant. What we need, standard=
-wise, is to modify the rules for accessing objects and aliasing to allow a=
 stateless subobject to have the same address as <em>any</em> other object.=
 Because stateless objects have no value to access, we may not even need to=
 change [basic.lval]/10.</p>
<p>The address of a stateless subobject can be any address within the stora=
ge of the object that contains it. The standard need not specify exactly wh=
ich address.</p>
<p>Implementation-wise, the difficulty will be in changing how types are la=
id out. That is, modifying ABIs to allow member subobjects that have no siz=
e and enforcing EBO even when it might otherwise have been forbidden.</p>
<p>The behavior of the <em>user</em> converting pointers/references between=
 two unrelated stateless subobjects should still be undefined. We just need=
 rules to allow stateless subobjects to be assigned a memory location at th=
e discretion of the compiler, which may not be unique from other unrelated =
objects.</p>
<h3 id=3D"stateless-arrays">Stateless arrays</h3>
<p>This design expressly forbids the declaration of stateless member subobj=
ects that are arrayed. The reason for this has to do with pointer arithmeti=
c.</p>
<p>In C++, the following should be perfectly valid for any type <code>T</co=
de>, regarldess of where the array of <code>T</code> is declared:</p>
<pre><code>T t[5];
T *first =3D &amp;t[0];
T *last =3D first + 5;
assert(sizeof(T) * 5 =3D=3D last - first);</code></pre>
<p>The whole point of a stateless subobject is that it does not take up spa=
ce within another type. If the array above were a member of another type, t=
his code still ought to work. But, since <code>sizeof(T)</code> is non-zero=
, that means that those values have to take up space somewhere. Each pointe=
r has to be valid.</p>
<p>Under non-array conditions, the pointer to a stateless subobject could a=
lways have the same address as its container (recursively, to the last non-=
stateless container). Adding 1 to any such pointer will still be a valid ad=
dress; this is required because any object can be considered an array of 1 =
value ([expr.add]/4). If the containing class is an empty class with a size=
 of 1, then adding one to a stateless member's pointer is no less valid tha=
n adding 1 to the container's address.</p>
<p>When dealing with an array, this is not necessarily the case. If the sta=
teless array has a count larger than 1, and it is contained in an empty cla=
ss, there is no guarantee that adding a number larger than 1 will result in=
 a valid address for the purposes of iteration.</p>
<p>Several alternatives were considered:</p>
<ol style=3D"list-style-type: decimal">
<li><p>Declare that <code>sizeof</code> for stateless subobjects is zero. I=
 am not nearly familiar enough with the C++ standard to know the level of h=
orrors that this would unleash, but I can imagine that it's very bad. It wo=
uld also make it impossible to have a distinction between stateless subobje=
cts and stateless types, as the <code>sizeof</code> can be applied to a poi=
nter to the object, which cannot know if the object it points to is statele=
ss.</p></li>
<li><p>Declare that stateless subobjects which are arrayed will still take =
up space as though they were not declared <code>stateless</code>.</p></li>
<li><p>Forbid declaring arrays of stateless subobjects altogether.</p></li>
</ol>
<p>Option 1 is probably out due to various potential issues. #2 seems tempt=
ing, but it makes the use of <code>stateless T arr[4];</code> something of =
a lie. Earlier designs used #3, then switched to #2. But the current design=
 goes back to #3 for an important reason.</p>
<p>In the current design, it is the <em>use</em> of a type which is statele=
ss. Types can be declared stateless as well, but this really only means tha=
t all uses of them to declare objects will implicitly be stateless. So this=
 restricts how the type may be used, but not the semantics of it.</p>
<p>Because statelessness can be applied to any empty class at its point of =
use, if a user wants to be able to use an empty class in a non-stateless wa=
y, then they simply do not declare the class to be stateless.</p>
<p>And therefore, if you declare a class to be stateless, you truly intend =
for it to only be used as a subobject of another type. This would be useful=
 for a CRTP base class, for example, where it is a logical error to create =
an object of the class which is not a base class.</p>
<h3 id=3D"trivial-copyability">Trivial copyability</h3>
<p>Trivial copyability is another area that can be problematic with statele=
ss subobjects. We explicitly forbid trivial copying into a base class subob=
ject of another class ([basic.types]/2).</p>
<p>Similarly, we must explicitly forbid trivial copying into stateless subo=
bojects. Trivial copying <em>from</em> a stateless subobject should be OK. =
Though this is only &quot;OK&quot; in the sense that the program is not ill=
-formed or that there us undefined behavior. The value copied is undefined,=
 but that doesn't matter, since you could only ever use that value to initi=
alize a type that is layout compatible with an empty class. Namely, another=
 empty class. And empty classes have no value.</p>
<h3 id=3D"offsetof">offsetof</h3>
<p><code>offsetof</code> will obviously not be affected by stateless subobj=
ect members of another type. However, if <code>offsetof</code> is applied t=
o a stateless subobject, what is the result?</p>
<p>I would suggest that this either be undefined or 0.</p>
<h1 id=3D"potential-issues">Potential issues</h1>
<h2 id=3D"identity">Empty object identity</h2>
<p>A type with no data members is empty of valid data. It has no real value=
 representation. But under current C++ rules, it does have one important pi=
ece of state: itself.</p>
<p>The present rules of C++ require that every object have identity that is=
 (almost) unique from every other object. There are two exceptions to this:=
 a member subobject of a type may have a pointer value equal to the contain=
ing object. And base class subobject(s) may have pointer values equal to th=
eir derived classes.</p>
<p>However, the current rules effectively guarantee that, for any two disti=
nct objects of the same dynamic type <code>T</code>, they will have <em>dif=
ferent addresses</em>. As such, it is possible for an empty type to have ou=
t-of-object state by using its <code>this</code> pointer as a unique identi=
fier to access said state.</p>
<p>The current version of stateless subobjects changes things so that it br=
eaks that rule. If a type has two stateless subobjects of the same type, th=
e compiler may assign them the same address. And if that type expects its o=
bject to have identity, the object's functionality may be broken.</p>
<p>There are ways to resolve this problem.</p>
<h3 id=3D"explicitly-forbid-the-problem-cases">Explicitly forbid the proble=
m cases</h3>
<p>The problem arises because two stateless subobjects of the same type exi=
st within the same containing type. So we can simply forbid that. This is a=
 special case rule, much as we declare that types stop being standard layou=
t if their first NSDM is the same type as one of their empty base classes.<=
/p>
<p>We declare that an object which has more than one stateless subobject of=
 the same type (whether base class or member) is il-formed. This would be r=
ecursive, up the subobject containment hierarchy. However, it stops looking=
 if it recurses through most non-stateless subobjects.</p>
<p>Here are some examples to clarify things:</p>
<pre><code>stateless struct no_state{};
struct multiple
{
    no_state ns1;
    no_state ns2;   //Il-formed, same type as before.
};

struct empty        //Empty, but not implicitly stateless.
{
    no_state ns1;
};

struct contain1
{
    stateless empty e;
    no_state ns2;   //Il-formed, contains same type as stateless e.ns1
};

struct contain2 : stateless empty
{
    no_state ns2;   //Il-formed, contains same type as stateless base class=
 empty::ns1
};

struct works
{
    empty e;
    no_state ns2;   //Fine. `e` is empty but *not* stateless
                    //Thus `e` has identity, and so do all of its members.
};

struct fails : empty
{
    no_state ns2;   //Il-formed. Base class is empty and by standard-layout=
 rules
                    //has no identity.
};</code></pre>
<p>As noted in the last example, this would also require adding rules deali=
ng with EBO interaction with stateless subobjects. There would also need to=
 be a &quot;first member&quot; for non-stateless subobjects, similar to the=
 standard layout rule.</p>
<p>This would be quite complicated, but I think such rules can be hashed ou=
t.</p>
<p>A first-pass at such a rule would be, for each stateless subobject, chec=
k:</p>
<ul>
<li>Any stateless subobjects in the same object.</li>
<li>Any empty-but-not-stateless base class subobjects.
<ul>
<li>Both of these recurse up the containment hierarchy.</li>
</ul></li>
<li>The first non-stateless member subobject.
<ul>
<li>Recursively check for stateless subobjects and empty-but-not-stateless =
base classes.</li>
<li>Recursively check the first member subobject of each type.</li>
</ul></li>
</ul>
<h3 id=3D"ignore-the-problem">Ignore the problem</h3>
<p>We could just ignore the problem. After all, it would only be a problem =
in the most rare of circumstances, where:</p>
<ol style=3D"list-style-type: decimal">
<li><p>The user has created an empty type that gains state state through it=
s identity.</p></li>
<li><p>The user (or another user) uses this type as a stateless subobject.<=
/p></li>
<li><p>The user (or another user) uses this type as a stateless subobject m=
ore than once.</p></li>
</ol>
<p>I would suggest that users who do #1 can defend themselves against #2 si=
mply by declaring that the type has an NSDM of type <code>char</code>. Alte=
rnatively, we can define special syntax to allow users to actively prevent =
an empty type from being used as a stateless subobject.</p>
<h3 id=3D"there-is-no-problem">There is no problem</h3>
<p>Alternatively, we could redefine the problem. It only occurs when two or=
 more stateless subobjects exist within the same stateless mass. So we can =
simply declare that, when that happens, the objects are <em>not distinct ob=
jects</em>. One is an alias for the other.</p>
<p>As such, we have identity only of the ultimate non-stateless containing =
subobject. If the user expects (given the above example) <code>multiple::ns=
1</code> and <code>multiple::ns2</code> to be different objects, then the u=
ser is simply wrong to think so.</p>
<p>This sounds like the previous suggestion, but it really is different. In=
 the previous suggestion, it's a corner case. With this suggestion, we conc=
eptually re-evaluate what it means for a subobject to be stateless. That be=
ing stateless means that the object shares its identity with all other stat=
eless objects in the same non-stateless container.</p>
<p>That is, rather than declaring it to be an unfortunate bug, we embrace i=
t as a feature. As such, we <em>actively forbid</em> implementations from a=
llowing different stateless instances at the same level from having differe=
nt addresses. <code>multiple::ns1</code> <em>must</em> have the same addres=
s as <code>multiple::ns2</code>.</p>
<p>This also means that there is only one such object. This creates an inte=
resting problem with object lifetime and construction/destruction calls. In=
deed, any per-member compiler-generation function call.</p>
<p>On the one hand, if there is only one such object, then there should onl=
y be one constructor and one destructor call. But there are two member vari=
ables, and having only one call would be weird. Indeed, the two objects cou=
ld be subobjects of different stateless subobjects.</p>
<p>What's worse is that, if the user declares a copy constructor or assignm=
ent operator, they will have to list both objects in their member initializ=
er. If they declare an assignment operator, they have to list both objects.=
</p>
<p>So the only logical alternative here is that you <em>have</em> to call t=
he constructor multiple times. In which case, the object model has to chang=
e.</p>
<p>In order for stateless subobjects of any kind to work, we declare that m=
any objects of different types live in the same region of storage. In order=
 for two stateless subobjects of the same type to live in the same region o=
f storage, we have to declare that, since they have no value representation=
, then a memory location can conceptually hold any number of stateless subo=
bjects of any type. Even if they are the same type.</p>
<p>As such, constructing one member subobject begins its lifetime. Construc=
ting a second begins its lifetime. This leaves you with two objects of the =
same type in the same location of memory.</p>
<h3 id=3D"only-stateless-types-can-lose-identity">Only stateless types can =
lose identity</h3>
<p>This is effectively a combination of the first and third ideas.</p>
<p>As currently presented here, a type declared <code>stateless</code> has =
very few differences from a type that is empty. The primary difference is t=
hat, if it is used to declare a subobject, then that declaration will impli=
citly be <code>stateless</code>.</p>
<p>However, we can add certain features, based on the fact that the writer =
of the class declared it to be <code>stateless</code>. By declaring the cla=
ss as such, we can define that the user has declared that the class <em>its=
elf</em> lacks unique identity. As such, the user has entered into a contra=
ct that makes it clear that two subobjects of the same containing object re=
fer to the same object.</p>
<p>Thus, we apply the third idea, but only to types which the user has expl=
icitly blessed as such.</p>
<p>For all empty-but-not-stateless types, we apply the first rule. If we de=
clare a <code>stateless</code> subobjects for a type that is empty-but-not-=
stateless, compilation will fail if that type could alias with another inst=
ance of itself elsewhere within that object, recursively up the subobject h=
ierarchy.</p>
<h3 id=3D"only-stateless-types-can-be-stateless-subojbects.">Only stateless=
 types can be stateless subojbects.</h3>
<p>With this solution, we use the assumption implicit in the previous idea =
(that if you declare a type to be <code>stateless</code>, then you are sayi=
ng that your code will not rely on it having unique identity). And we simpl=
y say that a subobject can only be declared stateless if its type is explic=
itly declared stateless.</p>
<p>This solves the unique identity problem by forcing the user to explicitl=
y specify when it is OK to lose unique identity. However, it fails to solve=
 the general problem of people using EBO as a means for having a stateless =
subobject. They will continue to do so, as the set of <code>stateless</code=
> declared objects will always be smaller than the set of empty types that =
qualify for EBO.</p>
<h2 id=3D"the-unknown">The Unknown</h2>
<p>One of the most difficult aspects of dealing with any form of stateless =
type system is that it represents something that is very new and very compl=
icated for C++ to deal with. As such, the wording for this needs to be quit=
e precise and comprehensive, lest we introduce subtle bugs into the standar=
d.</p>
<p>A good spec doctor needs to be involved with the standardization of this=
 feature.</p>
<h1 id=3D"alternative-designs-explored">Alternative Designs Explored</h1>
<p>There has been many alternatives towards achieving the same ends. Every =
such alternative has to deal with 2 fundamental rules of the C++ object mod=
el:</p>
<ol style=3D"list-style-type: decimal">
<li>Objects are defined by a region of storage.</li>
<li>Two different object instances have different regions of storage.</li>
</ol>
<p>This current proposal is designed to avoid changes to rule #1. Stateless=
 subobjects in this proposal still have a non-zero size. Instead, changes t=
o rule #2 are made to permit such subobjects to be able to not disturb the =
layout of their container.</p>
<p>Other alternatives take a different approach to dealing with these rules=
..</p>
<h2 id=3D"magic-standard-library-wrapper-type">Magic standard library wrapp=
er type</h2>
<p><a href=3D"https://groups.google.com/a/isocpp.org/d/msg/std-proposals/sA=
dqngl8pew/xCjHCLpuAAAJ">This idea</a> is focused on just the specific case =
of having empty classes potentially take up no space in their containing cl=
asses.</p>
<p>It would essentially declare a standard library type that is, in the con=
text of this proposal, something like this:</p>
<pre><code>template&lt;typename T&gt;
stateless(auto) struct allow_zero_size : public T {...};</code></pre>
<p>It is a wrapper which, when used as an NSDM, will not take up any space =
in its containing object if the given type is empty. And if it is not, then=
 it will.</p>
<p>The theoretical idea behind this is that it doesn't require new syntax. =
And in that proposal, <code>allow_zero_size</code> would not be forbidden f=
rom being in arrays or any of the other forbearances that this proposal for=
bids stateless types from.</p>
<p>This makes the behavior of such a type rather more difficult to specify.=
 The standard would still need to have changes to allow subobojects which t=
ake up no space to work, since users have to be able to get pointers/refere=
nces to them and the like. Once that work is done, exactly how you specify =
that a subobject takes up no space does not really matter.</p>
<h2 id=3D"stateless-by-type-declaration">Stateless by type declaration</h2>
<p>An older version of this idea permitted statelessness in a form similar =
to what is specified here. But that design evolved from the needs of inner =
classes and mixins, where it was solely on an implementation of a type to b=
e used for a specific purpose.</p>
<p>As such, in that design, a class was declared stateless. Once this was d=
one, that type could only be used to declare objects as direct subobject of=
 another type, and they would be implicitly stateless. Since both inner cla=
sses and mixins are intended for only those uses, that was not a significan=
t limitation.</p>
<p>The problem with this solution is that it does not solve the general sta=
teless problem outlined in the <a href=3D"#motivation">motivation</a> secti=
on.</p>
<h1 id=3D"changelist">Changelist</h1>
<h2 id=3D"from-pre-release-v2">From pre-release v2:</h2>
<ul>
<li>Added details about the empty object identity problem, as well as a num=
ber of potential solutions.</li>
</ul>
<h2 id=3D"from-pre-release-v1">From pre-release v1:</h2>
<ul>
<li><p>Clarified that stateless types act like regular empty types in all c=
ases except when declared as direct subobjects of classes.</p></li>
<li><p>Explicitly noted that the alignment of stateless subobjects will be =
respected by their containers.</p></li>
</ul>
<h1 id=3D"acknowledgments">Acknowledgments</h1>
<p>From the C++ Future Discussions forum:</p>
<ul>
<li>Avi Kivity</li>
<li>A. Jo=C3=ABl Lamotte, who's original thread on <a href=3D"https://group=
s.google.com/a/isocpp.org/d/msg/std-proposals/u35GIuJECcQ/Yorc58iiBwAJ">Inl=
ine Classes</a> was the seed for this idea.</li>
<li>Vicente J. Botet Escriba</li>
<li>Matt Calabrese</li>
<li>Andrew Tomazos</li>
<li>Matthew Woehlke</li>
<li>Bengt Gustafsson</li>
<li>Thiago Macieira, who initially identified the unique identity problem.<=
/li>
</ul>
<div class=3D"footnotes">
<hr />
<ol>
<li id=3D"fn1"><p>It may be reasonable to use the logical <code>or</code> b=
etween the two, instead of failing on a mis-match.<a href=3D"#fnref1">=E2=
=86=A9</a></p></li>
<li id=3D"fn2"><p>In theory, at any rate. <a href=3D"#identity">There is a =
discussion</a> of a case where empty types can effectively have state.<a hr=
ef=3D"#fnref2">=E2=86=A9</a></p></li>
</ol>
</div>
</body>
</html>

------=_Part_1162_2093239738.1468692585857
Content-Type: text/x-markdown; charset=UTF-8; name="Stateless Subobjects.md"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename="Stateless Subobjects.md"
X-Attachment-Id: 5e2f76d1-0ae5-432c-8314-750596dd5a0a
Content-ID: <5e2f76d1-0ae5-432c-8314-750596dd5a0a>

% Stateless Subobjects and Types, pre-release v3
%
% July 13, 2016

This proposal specifies the ability to declare member and base class subobj=
ects which do not take up space in the objects they are contained within. I=
t also allows the user to define classes which will always be used in such =
a fashion.

# Motivation and Scope {#motivation}

An object is stateless, conceptually speaking, if it has no non-static data=
 members. As such, the state of any particular instance is no different fro=
m another. Because of this, there is no conceptual reason why a stateless o=
bject needs to have a region of storage associated with it.

In C++, a class would be stateless if it has no non-static data members (NS=
DMs) and all of its base classes likewise are stateless as well. `is_empty_=
v` qualifies as a useful test, but technically other classes could qualify =
as well (those with virtual members/base classes).

There are many times when a user wants to use a class that the user provide=
s, but the class may or may not be logically stateless. If it is stateless,=
 then it would be best if the class which uses it would not grow in size si=
mply due to the presence of the stateless subobject. After all, a conceptua=
lly stateless object does not need to take up space to do its job.

To avoid this, users will frequently use standard layout rules and the empt=
y base optimization to allow them to have access to a stateless subobject:

=09template<typename Alloc>
=09struct DataBlock : public Alloc
=09{
=09};

In this case, if `Alloc` is empty, then so long as `DataBlock` follows stan=
dard layout rules, the user is guaranteed that `DataBlock` is no larger tha=
n it would have been if `Alloc` were not empty. Even if it does not follow =
standard layout, the compiler is free to optimize the empty base `Alloc` aw=
ay.

There are of course problems with such a use. If `Alloc` is not empty (and =
`DataBlock` does not require that it is), and `Alloc` declares a virtual fu=
nction, it is possible that `DataBlock<Alloc>` will accidentally override t=
hat virtual function. Or not quite override it and cause a compile error. W=
hereas if `Alloc` were a non-static data member, this could easily be avoid=
ed.

Equally importantly, this use of `Alloc` is simply not how a user would nat=
urally write this class. Inheritance is supposed to model an "is a" relatio=
nship. Yet conceptually, `DataBlock` is not an `Alloc`; it *has* an `Alloc`=
.. `DataBlock` uses inheritance, not to model a relationship, but as an opti=
mization tool, to keep the class from growing unnecessarily.

The intent of this proposal is to permit, among other things, classes like =
`DataBlock` to declare `Alloc` as a non-static data member. And if `Alloc` =
is empty, then `DataBlock` can use syntax to make the `Alloc` NSDM take up =
no space in `DataBlock`'s layout.

This would also be recursive, so that if `Alloc` had no NSDMs, and `DataBlo=
ck<Alloc>` had no NSDMs besides the `Alloc` member, then `DataBlock<Alloc>`=
 would also be considered an empty type. And therefore, some other type cou=
ld use it in a stateless fashion.

# Design

We define two concepts: stateless subobjects and stateless classes. A state=
less class is really just shorthand for the former; it declares that instan=
ces of the class can only be created as stateless subobjects of some other =
type.

Note: The following syntax is entirely preliminary. This proposal is not we=
dded to the idea of introducing a new keyword or somesuch. This syntax is h=
ere simply for the sake of understanding how the functionality should gener=
ally be specified. The eventual syntax could be a contextual keyword like `=
final` and `override`, or it could be something else.

### Stateless subobojects

A non-static data member subobject of a type can be declared stateless with=
 the following syntax:

=09struct Data
=09{
=09=09stateless Type val;
=09};
=09
A base class subobject of a type can be declared stateless with the followi=
ng syntax:

=09struct Data : public stateless Type
=09{
=09=09...
=09};

In both cases, if `Type` is not an empty class, then this is a compile erro=
r. `stateless` cannot be applied to a base class which uses `virtual` inher=
itance.

Member subobjects that are arrayed cannot be declared with `stateless` prop=
erty. Variables which are not non-static data members cannot be declared wi=
th the stateless property.

`stateless` cannot be applied to a member of a `union` class.

The stateless property can be conditional, based on a compile-time conditio=
n like `noexcept`. This is done as follows:

=09template<typename Alloc>
=09struct DataBlock
=09{
=09=09stateless(is_empty_v<Alloc>) Alloc a;
=09};

In this case, `a` will be a stateless member only if its type is empty. If =
the condition is false, then it is as if the stateless property were not ap=
plied to the subobject.

To facilitate common use patterns, the `stateless(auto)` syntax for subobje=
cts shall be equivalent to `stateless(std::is_empty_v<T>)`, where `T` is th=
e type of the subobject being declared.

### Stateless behavior

Stateless subobjects have no effect on the layout or size of their containi=
ng object. Similarly, the rules for standard layout types ignore the presen=
ce of any stateless subobjects. And thus, two classes can be layout compati=
ble even if they differ by the presence of stateless subobjects.

Stateless subobjects otherwise have the same effects on their containing ty=
pes as regular subobjects do. For example, a stateless subobject can cause =
its container to not be trivially copyable, if it has a non-trivial copy co=
nstructor (even though the object by definition has no state to copy).

The definition of "empty class" (per `std::is_empty`) must now be expanded.=
 The rules for an empty class are:

* Non-union class.
* No virtual functions.
* No virtual base classes.
* No non-empty base classes.
* No non-stateless NSDMs.

In all other ways, except where detailed below, a stateless subobject works=
 identically to a non-stateless one. Stateless subobjects are initialized a=
nd destroyed just as if they were not stateless. Stateless subobjects under=
go copy and move construction and assignment along with all other subobject=
s (though they will likely not be doing much). In particular, stateless sub=
objects are still members/base classes of the types that contain them, so a=
ggregate initialization of members (and bases) will still have to take them=
 into account:

=09struct foo {};

=09struct aggregate
=09{
=09  stateless foo f;
=09  int b;
=09};

=09//It may have no state, but `f` must still be initialized.
=09aggregate agg =3D {{}, 4};

Note that the alignment of a stateless subobject will still impact the alig=
nment of the containing class. A `stateless` member declaration can include=
 an `alignas` specifier as well.

### Stateless types

The stateless property can be applied to (non-union) types as well:

=09stateless class ClassName : BaseClasses
=09{
=09=09...
=09};

The `stateless` keyword must be consistently associated with any forward de=
clarations for stateless types.

=09class ClassName;  //Not a stateless type.

=09stateless class ClassName  //Compiler error: you told me it wasn't state=
less before.
=09{
=09};

And vice-versa.

A stateless class definition is ill-formed if the class is not empty (per t=
he expanded rules for empty classes).

The size of a stateless class is not modified by being stateless. Therefore=
, the size of a stateless class shall be no different from the size of any =
other empty class.

The statelessness of a type can be conditional, just like subobjects:

=09template<typename T>
=09stateless(is_empty_v<T>) struct Foo : public T {};
=09
Here, `Foo` may or may not be stateless, depending on whether `T` is empty.=
 If the constant expression evaluates to `false`, then the class is not sta=
teless.

To make certain conditions easier, there will be the `stateless(auto)` synt=
ax. When applied to a class declaration, `stateless(auto)` will cause the c=
lass to be stateless if the class is empty. If the class is not empty, then=
 the class will not be stateless.

When a stateless class is used to create an object in a way that cannot hav=
e `stateless` applied to it, then the code behaves just as it would if the =
class did not have the `stateless` keyword. Therefore, you can heap allocat=
e arrays of stateless classes, and they will function just like any heap al=
located array of empty classes. You can declare an automatic variable of a =
stateless type, and it will behave as any empty class (note: implementation=
s may optimize such objects to take up no stack space if possible, but they=
 are not required to do so).

However, when a stateless class is used to declare a direct subobject of an=
other type, that subobject will be implicitly stateless. It is perfectly va=
lid to explicitly specify `stateless` on a member/base class of a stateless=
 type as well. If the conditions on the two `stateless` properties do not a=
gree (one resolves to true and the other false), then the program is il-for=
med.[^1]

Declaring an array of a stateless type as an NSDM is forbidden. Stateless t=
ypes may not be used as members of a union.

The standard library does not need to have a traits class to detect if a ty=
pe is stateless. A type with such a declaration can be used in any way that=
 any type can, so `is_empty` is sufficient.

### Stateless anonymous types

Statelessness can be applied to anonymous types as well:

=09stateless(auto) struct
=09{
=09=09Data d;
=09} varName;

The `stateless` property applies to the struct declaration, not the variabl=
e. As such, `decltype(varName)` will be a stateless type if `Data` is a sta=
teless type. Such declarations can only be made as non-static data members.

## Implementation and Restrictions

In a perfect world, the above would be the only restrictions on stateless t=
ypes. C++ of course is never perfect.

### Memory locations

In C++ as it currently stands, every object needs to have a memory location=
.. And two separate objects of unrelated types cannot have the *same* memory=
 location.

Stateless subobojects effectively have to be able to break this rule. The m=
emory location of a stateless subobject is more or less irrelevant. Since t=
he type is stateless, there is no independent state to access. So one insta=
nce is functionally no different from another.[^2]

As such, the general idea is that a stateless subobject could have any addr=
ess within the storage of the object which contains it. This means that a s=
tateless subobject can have the same address as any other subobject in its =
containing object's type.

This is not really an implementation problem, since stateless subobojects b=
y their very nature have no state to access. As such, the specific address =
of their `this` pointer is irrelevant. What we need, standard-wise, is to m=
odify the rules for accessing objects and aliasing to allow a stateless sub=
object to have the same address as *any* other object. Because stateless ob=
jects have no value to access, we may not even need to change [basic.lval]/=
10.

The address of a stateless subobject can be any address within the storage =
of the object that contains it. The standard need not specify exactly which=
 address.

Implementation-wise, the difficulty will be in changing how types are laid =
out. That is, modifying ABIs to allow member subobjects that have no size a=
nd enforcing EBO even when it might otherwise have been forbidden.

The behavior of the *user* converting pointers/references between two unrel=
ated stateless subobjects should still be undefined. We just need rules to =
allow stateless subobjects to be assigned a memory location at the discreti=
on of the compiler, which may not be unique from other unrelated objects.

### Stateless arrays

This design expressly forbids the declaration of stateless member subobject=
s that are arrayed. The reason for this has to do with pointer arithmetic.

In C++, the following should be perfectly valid for any type `T`, regarldes=
s of where the array of `T` is declared:

=09T t[5];
=09T *first =3D &t[0];
=09T *last =3D first + 5;
=09assert(sizeof(T) * 5 =3D=3D last - first);

The whole point of a stateless subobject is that it does not take up space =
within another type. If the array above were a member of another type, this=
 code still ought to work. But, since `sizeof(T)` is non-zero, that means t=
hat those values have to take up space somewhere. Each pointer has to be va=
lid.

Under non-array conditions, the pointer to a stateless subobject could alwa=
ys have the same address as its container (recursively, to the last non-sta=
teless container). Adding 1 to any such pointer will still be a valid addre=
ss; this is required because any object can be considered an array of 1 val=
ue ([expr.add]/4). If the containing class is an empty class with a size of=
 1, then adding one to a stateless member's pointer is no less valid than a=
dding 1 to the container's address.

When dealing with an array, this is not necessarily the case. If the statel=
ess array has a count larger than 1, and it is contained in an empty class,=
 there is no guarantee that adding a number larger than 1 will result in a =
valid address for the purposes of iteration.

Several alternatives were considered:

1. Declare that `sizeof` for stateless subobjects is zero. I am not nearly =
familiar enough with the C++ standard to know the level of horrors that thi=
s would unleash, but I can imagine that it's very bad. It would also make i=
t impossible to have a distinction between stateless subobjects and statele=
ss types, as the `sizeof` can be applied to a pointer to the object, which =
cannot know if the object it points to is stateless.

2. Declare that stateless subobjects which are arrayed will still take up s=
pace as though they were not declared `stateless`.

3. Forbid declaring arrays of stateless subobjects altogether.

Option 1 is probably out due to various potential issues. #2 seems tempting=
, but it makes the use of `stateless T arr[4];` something of a lie. Earlier=
 designs used #3, then switched to #2. But the current design goes back to =
#3 for an important reason.

In the current design, it is the *use* of a type which is stateless. Types =
can be declared stateless as well, but this really only means that all uses=
 of them to declare objects will implicitly be stateless. So this restricts=
 how the type may be used, but not the semantics of it.

Because statelessness can be applied to any empty class at its point of use=
, if a user wants to be able to use an empty class in a non-stateless way, =
then they simply do not declare the class to be stateless.

And therefore, if you declare a class to be stateless, you truly intend for=
 it to only be used as a subobject of another type. This would be useful fo=
r a CRTP base class, for example, where it is a logical error to create an =
object of the class which is not a base class.

### Trivial copyability

Trivial copyability is another area that can be problematic with stateless =
subobjects. We explicitly forbid trivial copying into a base class subobjec=
t of another class ([basic.types]/2).

Similarly, we must explicitly forbid trivial copying into stateless suboboj=
ects. Trivial copying *from* a stateless subobject should be OK. Though thi=
s is only "OK" in the sense that the program is not ill-formed or that ther=
e us undefined behavior. The value copied is undefined, but that doesn't ma=
tter, since you could only ever use that value to initialize a type that is=
 layout compatible with an empty class. Namely, another empty class. And em=
pty classes have no value.

### offsetof

`offsetof` will obviously not be affected by stateless subobject members of=
 another type. However, if `offsetof` is applied to a stateless subobject, =
what is the result?

I would suggest that this either be undefined or 0.

# Potential issues

## Empty object identity {#identity}

A type with no data members is empty of valid data. It has no real value re=
presentation. But under current C++ rules, it does have one important piece=
 of state: itself.

The present rules of C++ require that every object have identity that is (a=
lmost) unique from every other object. There are two exceptions to this: a =
member subobject of a type may have a pointer value equal to the containing=
 object. And base class subobject(s) may have pointer values equal to their=
 derived classes.

However, the current rules effectively guarantee that, for any two distinct=
 objects of the same dynamic type `T`, they will have *different addresses*=
.. As such, it is possible for an empty type to have out-of-object state by =
using its `this` pointer as a unique identifier to access said state.

The current version of stateless subobjects changes things so that it break=
s that rule. If a type has two stateless subobjects of the same type, the c=
ompiler may assign them the same address. And if that type expects its obje=
ct to have identity, the object's functionality may be broken.

There are ways to resolve this problem.

### Explicitly forbid the problem cases

The problem arises because two stateless subobjects of the same type exist =
within the same containing type. So we can simply forbid that. This is a sp=
ecial case rule, much as we declare that types stop being standard layout i=
f their first NSDM is the same type as one of their empty base classes.

We declare that an object which has more than one stateless subobject of th=
e same type (whether base class or member) is il-formed. This would be recu=
rsive, up the subobject containment hierarchy. However, it stops looking if=
 it recurses through most non-stateless subobjects.

Here are some examples to clarify things:

=09stateless struct no_state{};
=09struct multiple
=09{
=09=09no_state ns1;
=09=09no_state ns2;=09//Il-formed, same type as before.
=09};

=09struct empty=09=09//Empty, but not implicitly stateless.
=09{
=09=09no_state ns1;
=09};

=09struct contain1
=09{
=09=09stateless empty e;
=09=09no_state ns2;=09//Il-formed, contains same type as stateless e.ns1
=09};

=09struct contain2 : stateless empty
=09{
=09=09no_state ns2;=09//Il-formed, contains same type as stateless base cla=
ss empty::ns1
=09};

=09struct works
=09{
=09=09empty e;
=09=09no_state ns2;=09//Fine. `e` is empty but *not* stateless
=09=09=09=09=09=09//Thus `e` has identity, and so do all of its members.
=09};

=09struct fails : empty
=09{
=09=09no_state ns2;=09//Il-formed. Base class is empty and by standard-layo=
ut rules
=09=09=09=09=09=09//has no identity.
=09};

As noted in the last example, this would also require adding rules dealing =
with EBO interaction with stateless subobjects. There would also need to be=
 a "first member" for non-stateless subobjects, similar to the standard lay=
out rule.

This would be quite complicated, but I think such rules can be hashed out.

A first-pass at such a rule would be, for each stateless subobject, check:

* Any stateless subobjects in the same object.
* Any empty-but-not-stateless base class subobjects.
=09* Both of these recurse up the containment hierarchy.
* The first non-stateless member subobject.
=09* Recursively check for stateless subobjects and empty-but-not-stateless=
 base classes.
=09* Recursively check the first member subobject of each type.

### Ignore the problem

We could just ignore the problem. After all, it would only be a problem in =
the most rare of circumstances, where:

1. The user has created an empty type that gains state state through its id=
entity.

2. The user (or another user) uses this type as a stateless subobject.

3. The user (or another user) uses this type as a stateless subobject more =
than once.

I would suggest that users who do #1 can defend themselves against #2 simpl=
y by declaring that the type has an NSDM of type `char`. Alternatively, we =
can define special syntax to allow users to actively prevent an empty type =
from being used as a stateless subobject.

### There is no problem

Alternatively, we could redefine the problem. It only occurs when two or mo=
re stateless subobjects exist within the same stateless mass. So we can sim=
ply declare that, when that happens, the objects are *not distinct objects*=
.. One is an alias for the other.

As such, we have identity only of the ultimate non-stateless containing sub=
object. If the user expects (given the above example) `multiple::ns1` and `=
multiple::ns2` to be different objects, then the user is simply wrong to th=
ink so.

This sounds like the previous suggestion, but it really is different. In th=
e previous suggestion, it's a corner case. With this suggestion, we concept=
ually re-evaluate what it means for a subobject to be stateless. That being=
 stateless means that the object shares its identity with all other statele=
ss objects in the same non-stateless container.

That is, rather than declaring it to be an unfortunate bug, we embrace it a=
s a feature. As such, we *actively forbid* implementations from allowing di=
fferent stateless instances at the same level from having different address=
es. `multiple::ns1` *must* have the same address as `multiple::ns2`.

This also means that there is only one such object. This creates an interes=
ting problem with object lifetime and construction/destruction calls. Indee=
d, any per-member compiler-generation function call.

On the one hand, if there is only one such object, then there should only b=
e one constructor and one destructor call. But there are two member variabl=
es, and having only one call would be weird. Indeed, the two objects could =
be subobjects of different stateless subobjects.

What's worse is that, if the user declares a copy constructor or assignment=
 operator, they will have to list both objects in their member initializer.=
 If they declare an assignment operator, they have to list both objects.

So the only logical alternative here is that you *have* to call the constru=
ctor multiple times. In which case, the object model has to change.

In order for stateless subobjects of any kind to work, we declare that many=
 objects of different types live in the same region of storage. In order fo=
r two stateless subobjects of the same type to live in the same region of s=
torage, we have to declare that, since they have no value representation, t=
hen a memory location can conceptually hold any number of stateless subobje=
cts of any type. Even if they are the same type.

As such, constructing one member subobject begins its lifetime. Constructin=
g a second begins its lifetime. This leaves you with two objects of the sam=
e type in the same location of memory.

### Only stateless types can lose identity

This is effectively a combination of the first and third ideas.

As currently presented here, a type declared `stateless` has very few diffe=
rences from a type that is empty. The primary difference is that, if it is =
used to declare a subobject, then that declaration will implicitly be `stat=
eless`.

However, we can add certain features, based on the fact that the writer of =
the class declared it to be `stateless`. By declaring the class as such, we=
 can define that the user has declared that the class *itself* lacks unique=
 identity. As such, the user has entered into a contract that makes it clea=
r that two subobjects of the same containing object refer to the same objec=
t.

Thus, we apply the third idea, but only to types which the user has explici=
tly blessed as such.

For all empty-but-not-stateless types, we apply the first rule. If we decla=
re a `stateless` subobjects for a type that is empty-but-not-stateless, com=
pilation will fail if that type could alias with another instance of itself=
 elsewhere within that object, recursively up the subobject hierarchy.

### Only stateless types can be stateless subojbects.

With this solution, we use the assumption implicit in the previous idea (th=
at if you declare a type to be `stateless`, then you are saying that your c=
ode will not rely on it having unique identity). And we simply say that a s=
ubobject can only be declared stateless if its type is explicitly declared =
stateless.

This solves the unique identity problem by forcing the user to explicitly s=
pecify when it is OK to lose unique identity. However, it fails to solve th=
e general problem of people using EBO as a means for having a stateless sub=
object. They will continue to do so, as the set of `stateless` declared obj=
ects will always be smaller than the set of empty types that qualify for EB=
O.

## The Unknown

One of the most difficult aspects of dealing with any form of stateless typ=
e system is that it represents something that is very new and very complica=
ted for C++ to deal with. As such, the wording for this needs to be quite p=
recise and comprehensive, lest we introduce subtle bugs into the standard.

A good spec doctor needs to be involved with the standardization of this fe=
ature.

# Alternative Designs Explored

There has been many alternatives towards achieving the same ends. Every suc=
h alternative has to deal with 2 fundamental rules of the C++ object model:

1. Objects are defined by a region of storage.
2. Two different object instances have different regions of storage.

This current proposal is designed to avoid changes to rule #1. Stateless su=
bobjects in this proposal still have a non-zero size. Instead, changes to r=
ule #2 are made to permit such subobjects to be able to not disturb the lay=
out of their container.

Other alternatives take a different approach to dealing with these rules.

## Magic standard library wrapper type

[This idea](https://groups.google.com/a/isocpp.org/d/msg/std-proposals/sAdq=
ngl8pew/xCjHCLpuAAAJ) is focused on just the specific case of having empty =
classes potentially take up no space in their containing classes.

It would essentially declare a standard library type that is, in the contex=
t of this proposal, something like this:

=09template<typename T>
=09stateless(auto) struct allow_zero_size : public T {...};

It is a wrapper which, when used as an NSDM, will not take up any space in =
its containing object if the given type is empty. And if it is not, then it=
 will.

The theoretical idea behind this is that it doesn't require new syntax. And=
 in that proposal, `allow_zero_size` would not be forbidden from being in a=
rrays or any of the other forbearances that this proposal forbids stateless=
 types from.

This makes the behavior of such a type rather more difficult to specify. Th=
e standard would still need to have changes to allow subobojects which take=
 up no space to work, since users have to be able to get pointers/reference=
s to them and the like. Once that work is done, exactly how you specify tha=
t a subobject takes up no space does not really matter.

## Stateless by type declaration

An older version of this idea permitted statelessness in a form similar to =
what is specified here. But that design evolved from the needs of inner cla=
sses and mixins, where it was solely on an implementation of a type to be u=
sed for a specific purpose.

As such, in that design, a class was declared stateless. Once this was done=
, that type could only be used to declare objects as direct subobject of an=
other type, and they would be implicitly stateless. Since both inner classe=
s and mixins are intended for only those uses, that was not a significant l=
imitation.

The problem with this solution is that it does not solve the general statel=
ess problem outlined in the [motivation](#motivation) section.

# Changelist

## From pre-release v2:

* Added details about the empty object identity problem, as well as a numbe=
r of potential solutions.

## From pre-release v1:

* Clarified that stateless types act like regular empty types in all cases =
except when declared as direct subobjects of classes.

* Explicitly noted that the alignment of stateless subobjects will be respe=
cted by their containers.

# Acknowledgments

From the C++ Future Discussions forum:

* Avi Kivity
* A. Jo=C3=ABl Lamotte, who's original thread on [Inline Classes](https://g=
roups.google.com/a/isocpp.org/d/msg/std-proposals/u35GIuJECcQ/Yorc58iiBwAJ)=
 was the seed for this idea.
* Vicente J. Botet Escriba
* Matt Calabrese
* Andrew Tomazos
* Matthew Woehlke
* Bengt Gustafsson
* Thiago Macieira, who initially identified the unique identity problem.

[^1]: It may be reasonable to use the logical `or` between the two, instead=
 of failing on a mis-match.

[^2]: In theory, at any rate. [There is a discussion](#identity) of a case =
where empty types can effectively have state.
------=_Part_1162_2093239738.1468692585857--

.


Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Sun, 17 Jul 2016 03:51:57 -0700 (PDT)
Raw View
------=_Part_3245_1870941234.1468752717720
Content-Type: multipart/alternative;
 boundary="----=_Part_3246_391566813.1468752717720"

------=_Part_3246_391566813.1468752717720
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

When it comes to arrays of stateless objects I think there is a fourth=20
option worth considering:

4. arrays of stateless objects take no room in the declared scope, but=20
pointer arithmethics and indexing works as if sizeof(T) is 1, (which indeed=
=20
it is).

This allows loops over the array elements and pointer arithmetic and=20
similar operations to work as for any type. Of course you can't actually=20
access the array elements, but this doesn't matter as there is nothing=20
there anyway. I can't see that it would be worse to, say, do this:

stateless T arr[2];

arr[1].SomeMethod();   // Here you call SomeMethod() with a 'this' pointer=
=20
which does not point to a T.

than this:

stateless T s;
s.SomeMethod();

Den l=C3=B6rdag 16 juli 2016 kl. 20:09:46 UTC+2 skrev Nicol Bolas:
>
> Here's the next revision of the proposal.
>
> I've added an issues section that discusses the identity problem that=20
> we've discussed here, along with an exploration of possible solutions. No=
ne=20
> of those are integrated into the actual proposed design yet, which remain=
s=20
> as it was before.
>
> I'm really leaning towards the solution, where we forbid any stateless=20
> subobjects that violate unique identity, but allowing classes explicitly=
=20
> declared stateless to lack unique identity. In such cases, multiple objec=
ts=20
> of the same type would coexist in the same storage. So you'd get multiple=
=20
> constructors and destructors called on the same memory location. But sinc=
e=20
> you stated explicitly that the type was `stateless`, then you should know=
=20
> better than to use the `this` pointer in a way that expects unique identi=
ty.
>

--=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/fea12ace-db72-4c6a-8e53-70030bd4285b%40isocpp.or=
g.

------=_Part_3246_391566813.1468752717720
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">When it comes to arrays of stateless objects I think there=
 is a fourth option worth considering:<div><br></div><div>4. arrays of stat=
eless objects take no room in the declared scope, but pointer arithmethics =
and indexing works as if sizeof(T) is 1, (which indeed it is).<br><br>This =
allows loops over the array elements and pointer arithmetic and similar ope=
rations to work as for any type. Of course you can&#39;t actually access th=
e array elements, but this doesn&#39;t matter as there is nothing there any=
way. I can&#39;t see that it would be worse to, say, do this:</div><div><br=
></div><div>stateless T arr[2];</div><div><br></div><div>arr[1].SomeMethod(=
); =C2=A0 // Here you call SomeMethod() with a &#39;this&#39; pointer which=
 does not point to a T.</div><div><br></div><div>than this:</div><div><br><=
/div><div>stateless T s;</div><div>s.SomeMethod();<br><br>Den l=C3=B6rdag 1=
6 juli 2016 kl. 20:09:46 UTC+2 skrev Nicol Bolas:<blockquote class=3D"gmail=
_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;p=
adding-left: 1ex;"><div dir=3D"ltr">Here&#39;s the next revision of the pro=
posal.<br><br>I&#39;ve added an issues section that discusses the identity =
problem that we&#39;ve discussed here, along with an exploration of possibl=
e solutions. None of those are integrated into the actual proposed design y=
et, which remains as it was before.<br><br>I&#39;m really leaning towards t=
he solution, where we forbid any stateless subobjects that violate unique i=
dentity, but allowing classes explicitly declared stateless to lack unique =
identity. In such cases, multiple objects of the same type would coexist in=
 the same storage. So you&#39;d get multiple constructors and destructors c=
alled on the same memory location. But since you stated explicitly that the=
 type was `stateless`, then you should know better than to use the `this` p=
ointer in a way that expects unique identity.<br></div></blockquote></div><=
/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/fea12ace-db72-4c6a-8e53-70030bd4285b%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/fea12ace-db72-4c6a-8e53-70030bd4285b=
%40isocpp.org</a>.<br />

------=_Part_3246_391566813.1468752717720--

------=_Part_3245_1870941234.1468752717720--

.


Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Sun, 17 Jul 2016 03:59:43 -0700 (PDT)
Raw View
------=_Part_70_1960281588.1468753183205
Content-Type: multipart/alternative;
 boundary="----=_Part_71_1087860848.1468753183212"

------=_Part_71_1087860848.1468753183212
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

Sorry, that got sent before it was complete...

I was aiming to point out that the this pointer when calling the method on=
=20
the scalar s is just as invalid as when calling it for arr[1].

Oh, right now I see that this may cause an aliasing problem if the array=20
address range goes outside the surrounding object, and then for instance=20
two of those objects are allocated after each other on the heap. This=20
brings up an idea I have had in the back of my head for a couple of days:

Couldn't it just be demanded from the compiler to guarantee that no two=20
objects of the same type have the same address? Here is an example:

template<typename T> class Class {
    stateless T first;
    int x;



Den s=C3=B6ndag 17 juli 2016 kl. 12:51:58 UTC+2 skrev Bengt Gustafsson:
>
> When it comes to arrays of stateless objects I think there is a fourth=20
> option worth considering:
>
> 4. arrays of stateless objects take no room in the declared scope, but=20
> pointer arithmethics and indexing works as if sizeof(T) is 1, (which inde=
ed=20
> it is).
>
> This allows loops over the array elements and pointer arithmetic and=20
> similar operations to work as for any type. Of course you can't actually=
=20
> access the array elements, but this doesn't matter as there is nothing=20
> there anyway. I can't see that it would be worse to, say, do this:
>
> stateless T arr[2];
>
> arr[1].SomeMethod();   // Here you call SomeMethod() with a 'this' pointe=
r=20
> which does not point to a T.
>
> than this:
>
> stateless T s;
> s.SomeMethod();
>
> Den l=C3=B6rdag 16 juli 2016 kl. 20:09:46 UTC+2 skrev Nicol Bolas:
>>
>> Here's the next revision of the proposal.
>>
>> I've added an issues section that discusses the identity problem that=20
>> we've discussed here, along with an exploration of possible solutions. N=
one=20
>> of those are integrated into the actual proposed design yet, which remai=
ns=20
>> as it was before.
>>
>> I'm really leaning towards the solution, where we forbid any stateless=
=20
>> subobjects that violate unique identity, but allowing classes explicitly=
=20
>> declared stateless to lack unique identity. In such cases, multiple obje=
cts=20
>> of the same type would coexist in the same storage. So you'd get multipl=
e=20
>> constructors and destructors called on the same memory location. But sin=
ce=20
>> you stated explicitly that the type was `stateless`, then you should kno=
w=20
>> better than to use the `this` pointer in a way that expects unique ident=
ity.
>>
>

--=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/408f196b-f7a3-44b0-a249-95221d8ed2e1%40isocpp.or=
g.

------=_Part_71_1087860848.1468753183212
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Sorry, that got sent before it was complete...<div><br></d=
iv><div>I was aiming to point out that the this pointer when calling the me=
thod on the scalar s is just as invalid as when calling it for arr[1].</div=
><div><br></div><div>Oh, right now I see that this may cause an aliasing pr=
oblem if the array address range goes outside the surrounding object, and t=
hen for instance two of those objects are allocated after each other on the=
 heap. This brings up an idea I have had in the back of my head for a coupl=
e of days:</div><div><br></div><div>Couldn&#39;t it just be demanded from t=
he compiler to guarantee that no two objects of the same type have the same=
 address? Here is an example:</div><div><br></div><div>template&lt;typename=
 T&gt; class Class {</div><div>=C2=A0 =C2=A0 stateless T first;</div><div>=
=C2=A0 =C2=A0 int x;</div><div><br></div><div><br><br>Den s=C3=B6ndag 17 ju=
li 2016 kl. 12:51:58 UTC+2 skrev Bengt Gustafsson:<blockquote class=3D"gmai=
l_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;=
padding-left: 1ex;"><div dir=3D"ltr">When it comes to arrays of stateless o=
bjects I think there is a fourth option worth considering:<div><br></div><d=
iv>4. arrays of stateless objects take no room in the declared scope, but p=
ointer arithmethics and indexing works as if sizeof(T) is 1, (which indeed =
it is).<br><br>This allows loops over the array elements and pointer arithm=
etic and similar operations to work as for any type. Of course you can&#39;=
t actually access the array elements, but this doesn&#39;t matter as there =
is nothing there anyway. I can&#39;t see that it would be worse to, say, do=
 this:</div><div><br></div><div>stateless T arr[2];</div><div><br></div><di=
v>arr[1].SomeMethod(); =C2=A0 // Here you call SomeMethod() with a &#39;thi=
s&#39; pointer which does not point to a T.</div><div><br></div><div>than t=
his:</div><div><br></div><div>stateless T s;</div><div>s.SomeMethod();<br><=
br>Den l=C3=B6rdag 16 juli 2016 kl. 20:09:46 UTC+2 skrev Nicol Bolas:<block=
quote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left=
:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">Here&#39;s the next revi=
sion of the proposal.<br><br>I&#39;ve added an issues section that discusse=
s the identity problem that we&#39;ve discussed here, along with an explora=
tion of possible solutions. None of those are integrated into the actual pr=
oposed design yet, which remains as it was before.<br><br>I&#39;m really le=
aning towards the solution, where we forbid any stateless subobjects that v=
iolate unique identity, but allowing classes explicitly declared stateless =
to lack unique identity. In such cases, multiple objects of the same type w=
ould coexist in the same storage. So you&#39;d get multiple constructors an=
d destructors called on the same memory location. But since you stated expl=
icitly that the type was `stateless`, then you should know better than to u=
se the `this` pointer in a way that expects unique identity.<br></div></blo=
ckquote></div></div></blockquote></div></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/408f196b-f7a3-44b0-a249-95221d8ed2e1%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/408f196b-f7a3-44b0-a249-95221d8ed2e1=
%40isocpp.org</a>.<br />

------=_Part_71_1087860848.1468753183212--

------=_Part_70_1960281588.1468753183205--

.


Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Sun, 17 Jul 2016 05:02:37 -0700 (PDT)
Raw View
------=_Part_136_1410850196.1468756958001
Content-Type: multipart/alternative;
 boundary="----=_Part_137_1257174649.1468756958002"

------=_Part_137_1257174649.1468756958002
Content-Type: text/plain; charset=UTF-8

There it went again. I'm very sorry, but I think I pressed the space bar,
how could that send the message?

Here is the complete class head I was aiming for:

template<typename T> class Class {
    stateless T first[4];   // 0 bytes
    int x;               // 4 bytes
    stateless T second;  // 1 byte
};

Here first does not need its own storage as it does not alias with any
other T thanks to x. However, and here I'm uncertain, it seems that second
needs a dedicated byte for the case that
two Class objects are placed after each other, in which case the 'second'
member of the 1st object would alias with the 'first' member of the 2nd
object. Maybe the compiler can be required to recognize this case and put a
padding byte between the two variables in this case?

This also touches on the discussion of inheriting from T to get EBO and
then having the first NSDM being a T too, which creates an alias situation
today, which this rule would (potentially) remove.

This rule could also be refined to guarantee that there is no aliasing
between stateless variables and other variables even if they have different
types: Just assign a "unused" address to each stateless variable, i.e. an
address which is partway through another (stateful) variable. In my example
class above this means that to avoid aliasing between first[0] and x an
extra byte would be needed somewhere, probably best to place it after x and
use x+1 ... x+4 as the offsets for first's elements. If first was an array
3 or less this would not be needed though. If first was an array 2 or less
second's offset could also be crammed in as x + 3. It seems that this type
of rule would be best formulated as a QoI thing "compiler may select to
assign an offset inside another member as an alternative to wasting a byte".

I can't say that I find this idea particularly appealing but isn't it the
logical continuation of the thinking that the first stateless NSDM could
have the same offset as the surrounding object... if it can have the same
offset as the first non-empty member, then it should be equally ok to use
some other offset within the object for the second stateless member, and
least likely to alias in a bad way if this is an offset not pointing to the
start of any non-empty NSDM. This can then be generalized to (small)
arrays. In cases where no free offsets can be found padding bytes may have
to be added.

I think we are definitely making progress, but it is still unclear if this
reasoning leads all the way to a useful proposal. My conclusions are that
'stateless' on class and variable levels carry part of the semantic meaning
and that all four combinations are different:

non-stateless variable of a non-stateless type: This is the current case.

stateless variable of a non-stateless type: The variable does not need to
take up space if a "unused" offset can be found in the surrounding object.
This still allows keying on the object address as may be required by the
type's behavior. This also allows taking the address of the member and
using it as a key even if the variable's class is unaware.

non-stateless variable of a stateless type: While stateless types may not
have access to their own this pointer inside their methods surrounding code
may still take the address and use it as a key so the compiler must sill
find an unused offset to be able to optimize the storage away.

stateless variable of a stateless type: Now neither the class itself or the
surrounding object can get the address of the member so extra storage for
it can always be avoided.


I think this means roughly that stateless on a class indicates that there
is no this pointer with a particular address and stateless on a member
means that its address can't be taken. This is logical a the author of the
class knows it is empty and that accessing this is pointless. If such a
class needs a this as a key, well, then it is not a candidate for being
stateless after all. SImilarly the author of code with a stateless member
knows that the code does not rely on the member having a distinct address
(except maybe inside its own methods) or she would not use stateless
keyword.

As an aside: I don't think that the possibility to restrict a template to
only empty type parameter values is a good enough reason to complicate the
proposal with three versions of stateless, i.e.
stateless, stateless(bool) and stateless(auto). Also, with the stateless
class possibility it gets unclear to at least a fraction of programmers
whether stateless(auto) kicks in for all is_empty classes or only those
explicitly declared as stateless. Finally, on this issue, it seems that
what we typically want is partial specialization on whether a T is_empty or
not, not a hard error. And this can already be achieved using TMP, with or
without concepts.

With this question I conclude: Is this whole idea moot when we can use a
concept to specialize template classes not to even have a member if the
class passed in type is_empty?

--
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/a6d2b2b8-d5d8-4758-9e7d-98ac6efb98cd%40isocpp.org.

------=_Part_137_1257174649.1468756958002
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">There it went again. I&#39;m very sorry, but I think I pre=
ssed the space bar, how could that send the message?<div><br></div><div>Her=
e is the complete class head I was aiming for:<br><div><br></div><div><div =
class=3D"prettyprint" style=3D"border: 1px solid rgb(187, 187, 187); word-w=
rap: break-word; background-color: rgb(250, 250, 250);"><code class=3D"pret=
typrint"><div class=3D"subprettyprint"><span style=3D"color: #008;" class=
=3D"styled-by-prettify">template</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">&lt;</span><span style=3D"color: #008;" class=3D"st=
yled-by-prettify">typename</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> T</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">class</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><spa=
n style=3D"color: #606;" class=3D"styled-by-prettify">Class</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: #000;=
" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 stateless T first</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">[</span><span style=
=3D"color: #066;" class=3D"styled-by-prettify">4</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">];</span><span style=3D"color: #000;"=
 class=3D"styled-by-prettify"> =C2=A0 </span><span style=3D"color: #800;" c=
lass=3D"styled-by-prettify">// 0 bytes</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </span><span style=3D"color: =
#008;" class=3D"styled-by-prettify">int</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> x</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span =
style=3D"color: #800;" class=3D"styled-by-prettify">// 4 bytes</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 state=
less T second</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =C2=
=A0</span><span style=3D"color: #800;" class=3D"styled-by-prettify">// 1 by=
te</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">};</span></div=
></code></div><div><br></div><div>Here first does not need its own storage =
as it does not alias with any other T thanks to x. However, and here I&#39;=
m uncertain, it seems that second needs a dedicated byte for the case that<=
/div><div>two Class objects are placed after each other, in which case the =
&#39;second&#39; member of the 1st object would alias with the &#39;first&#=
39; member of the 2nd object. Maybe the compiler can be required to recogni=
ze this case and put a padding byte between the two variables in this case?=
=C2=A0</div><div><br></div><div>This also touches on the discussion of inhe=
riting from T to get EBO and then having the first NSDM being a T too, whic=
h creates an alias situation today, which this rule would (potentially) rem=
ove.=C2=A0</div><div><br></div><div>This rule could also be refined to guar=
antee that there is no aliasing between stateless variables and other varia=
bles even if they have different types: Just assign a &quot;unused&quot; ad=
dress to each stateless variable, i.e. an address which is partway through =
another (stateful) variable. In my example class above this means that to a=
void aliasing between first[0] and x an extra byte would be needed somewher=
e, probably best to place it after x and use x+1 ... x+4 as the offsets for=
 first&#39;s elements. If first was an array 3 or less this would not be ne=
eded though. If first was an array 2 or less second&#39;s offset could also=
 be crammed in as x + 3. It seems that this type of rule would be best form=
ulated as a QoI thing &quot;compiler may select to assign an offset inside =
another member as an alternative to wasting a byte&quot;.</div><div><br></d=
iv><div>I can&#39;t say that I find this idea particularly appealing but is=
n&#39;t it the logical continuation of the thinking that the first stateles=
s NSDM could have the same offset as the surrounding object... if it can ha=
ve the same offset as the first non-empty member, then it should be equally=
 ok to use some other offset within the object for the second stateless mem=
ber, and least likely to alias in a bad way if this is an offset not pointi=
ng to the start of any non-empty NSDM. This can then be generalized to (sma=
ll) arrays. In cases where no free offsets can be found padding bytes may h=
ave to be added.</div><div><br></div><div>I think we are definitely making =
progress, but it is still unclear if this reasoning leads all the way to a =
useful proposal. My conclusions are that &#39;stateless&#39; on class and v=
ariable levels carry part of the semantic meaning and that all four combina=
tions are different:</div><div><br></div><div>non-stateless variable of a n=
on-stateless type: This is the current case.</div><div><br></div><div>state=
less variable of a non-stateless type: The variable does not need to take u=
p space if a &quot;unused&quot; offset can be found in the surrounding obje=
ct. This still allows keying on the object address as may be required by th=
e type&#39;s behavior. This also allows taking the address of the member an=
d using it as a key even if the variable&#39;s class is unaware.</div><div>=
<br></div><div>non-stateless variable of a stateless type: While stateless =
types may not have access to their own this pointer inside their methods su=
rrounding code may still take the address and use it as a key so the compil=
er must sill find an unused offset to be able to optimize the storage away.=
</div><div><br></div><div>stateless variable of a stateless type: Now neith=
er the class itself or the surrounding object can get the address of the me=
mber so extra storage for it can always be avoided.</div><div><br></div><di=
v><br></div><div>I think this means roughly that stateless on a class indic=
ates that there is no this pointer with a particular address and stateless =
on a member means that its address can&#39;t be taken. This is logical a th=
e author of the class knows it is empty and that accessing this is pointles=
s. If such a class needs a this as a key, well, then it is not a candidate =
for being stateless after all. SImilarly the author of code with a stateles=
s member knows that the code does not rely on the member having a distinct =
address (except maybe inside its own methods) or she would not use stateles=
s keyword.</div><div><br></div><div>As an aside: I don&#39;t think that the=
 possibility to restrict a template to only empty type parameter values is =
a good enough reason to complicate the proposal with three versions of stat=
eless, i.e.</div><div>stateless, stateless(bool) and stateless(auto). Also,=
 with the stateless class possibility it gets unclear to at least a fractio=
n of programmers whether stateless(auto) kicks in for all is_empty classes =
or only those explicitly declared as stateless. Finally, on this issue, it =
seems that what we typically want is partial specialization on whether a T =
is_empty or not, not a hard error. And this can already be achieved using T=
MP, with or without concepts.</div></div></div><div><br></div><div>With thi=
s question I conclude: Is this whole idea moot when we can use a concept to=
 specialize template classes not to even have a member if the class passed =
in type is_empty?</div></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/a6d2b2b8-d5d8-4758-9e7d-98ac6efb98cd%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/a6d2b2b8-d5d8-4758-9e7d-98ac6efb98cd=
%40isocpp.org</a>.<br />

------=_Part_137_1257174649.1468756958002--

------=_Part_136_1410850196.1468756958001--

.


Author: Avi Kivity <avi@scylladb.com>
Date: Sun, 17 Jul 2016 18:53:56 +0300
Raw View
This is a multi-part message in MIME format.
--------------8F4B7C765D56816EC4CE3277
Content-Type: text/plain; charset=UTF-8; format=flowed

Thanks a lot for this.  I've been meaning to come back to it "later",
but your proposal is better than anything I would have come up with.


On 07/13/2016 09:18 PM, Nicol Bolas wrote:
> Here's a small update to the idea, after receiving commentary. It
> explains the behavior of stateless types hopefully more explicitly. It
> also adds a notation that stateless subobjects still impose their
> alignments on their containing types. So if you declare that an empty
> class has 8 byte alignment, then classes which statelessly use it will
> have at least 8 byte alignment. Even though it doesn't take up size.
>
> Also, I've been thinking about complexity reduction (this isn't
> reflected in the new version). I'm starting to think that `stateless`
> doesn't need full constant-expression conditionals.
>
> At subobject declarations, there are 3 scenarios of interest: 1) The
> user requires the subobject to be stateless and therefore the type
> must be empty. 2) The user wants the subobject to be stateless if the
> type allows that, but if not then it won't be stateless. 3) The user
> doesn't care.
>

Scenario 2 will be the most common one,  I imagine, and the syntax
should reflect that.

> With type declarations, there are 3 scenarios of interest: 1) The user
> wants all potentially stateless uses of the type to be stateless, so
> fail if the type is non-empty. 2) The user wants all potentially
> stateless uses of the type to be stateless /if/ the type is empty, but
> otherwise be non-stateless. 3) The user does not want all potentially
> stateless uses of the type to be stateless.
>
> Even something like `std::pair` doesn't need a conditional. A
> `pair<stateless1, stateless2>` is an empty type, and therefore we
> could declare that `pair` would be stateless if both types passed to
> it are stateless.
> --
> 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
> <mailto:std-proposals+unsubscribe@isocpp.org>.
> To post to this group, send email to std-proposals@isocpp.org
> <mailto:std-proposals@isocpp.org>.
> To view this discussion on the web visit
> https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/3ffd6df6-ba77-414c-aeef-7ec23206bb88%40isocpp.org
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/3ffd6df6-ba77-414c-aeef-7ec23206bb88%40isocpp.org?utm_medium=email&utm_source=footer>.

--
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/ed35bb0d-cbc3-a2ab-b58b-3d635beb1f39%40scylladb.com.

--------------8F4B7C765D56816EC4CE3277
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<html>
  <head>
    <meta content=3D"text/html; charset=3Dutf-8" http-equiv=3D"Content-Type=
">
  </head>
  <body bgcolor=3D"#FFFFFF" text=3D"#000000">
    <p>Thanks a lot for this.=C2=A0 I've been meaning to come back to it
      "later", but your proposal is better than anything I would have
      come up with.<br>
    </p>
    <br>
    <div class=3D"moz-cite-prefix">On 07/13/2016 09:18 PM, Nicol Bolas
      wrote:<br>
    </div>
    <blockquote
      cite=3D"mid:3ffd6df6-ba77-414c-aeef-7ec23206bb88@isocpp.org"
      type=3D"cite">
      <div dir=3D"ltr">Here's a small update to the idea, after receiving
        commentary. It explains the behavior of stateless types
        hopefully more explicitly. It also adds a notation that
        stateless subobjects still impose their alignments on their
        containing types. So if you declare that an empty class has 8
        byte alignment, then classes which statelessly use it will have
        at least 8 byte alignment. Even though it doesn't take up size.<br>
        <br>
        Also, I've been thinking about complexity reduction (this isn't
        reflected in the new version). I'm starting to think that
        `stateless` doesn't need full constant-expression conditionals.<br>
        <br>
        At subobject declarations, there are 3 scenarios of interest: 1)
        The user requires the subobject to be stateless and therefore
        the type must be empty. 2) The user wants the subobject to be
        stateless if the type allows that, but if not then it won't be
        stateless. 3) The user doesn't care.<br>
        <br>
      </div>
    </blockquote>
    <br>
    Scenario 2 will be the most common one,=C2=A0 I imagine, and the syntax
    should reflect that.<br>
    <br>
    <blockquote
      cite=3D"mid:3ffd6df6-ba77-414c-aeef-7ec23206bb88@isocpp.org"
      type=3D"cite">
      <div dir=3D"ltr">With type declarations, there are 3 scenarios of
        interest: 1) The user wants all potentially stateless uses of
        the type to be stateless, so fail if the type is non-empty. 2)
        The user wants all potentially stateless uses of the type to be
        stateless <i>if</i> the type is empty, but otherwise be
        non-stateless. 3) The user does not want all potentially
        stateless uses of the type to be stateless.<br>
        <br>
        Even something like `std::pair` doesn't need a conditional. A
        `pair&lt;stateless1, stateless2&gt;` is an empty type, and
        therefore we could declare that `pair` would be stateless if
        both types passed to it are stateless.<br>
      </div>
      -- <br>
      You received this message because you are subscribed to the Google
      Groups "ISO C++ Standard - Future Proposals" group.<br>
      To unsubscribe from this group and stop receiving emails from it,
      send an email to <a moz-do-not-send=3D"true"
        href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposals+=
unsubscribe@isocpp.org</a>.<br>
      To post to this group, send email to <a moz-do-not-send=3D"true"
        href=3D"mailto:std-proposals@isocpp.org">std-proposals@isocpp.org</=
a>.<br>
      To view this discussion on the web visit <a
        moz-do-not-send=3D"true"
href=3D"https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/3ffd6d=
f6-ba77-414c-aeef-7ec23206bb88%40isocpp.org?utm_medium=3Demail&amp;utm_sour=
ce=3Dfooter"><a class=3D"moz-txt-link-freetext" href=3D"https://groups.goog=
le.com/a/isocpp.org/d/msgid/std-proposals/3ffd6df6-ba77-414c-aeef-7ec23206b=
b88%40isocpp.org">https://groups.google.com/a/isocpp.org/d/msgid/std-propos=
als/3ffd6df6-ba77-414c-aeef-7ec23206bb88%40isocpp.org</a></a>.<br>
    </blockquote>
    <br>
  </body>
</html>

<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/ed35bb0d-cbc3-a2ab-b58b-3d635beb1f39%=
40scylladb.com?utm_medium=3Demail&utm_source=3Dfooter">https://groups.googl=
e.com/a/isocpp.org/d/msgid/std-proposals/ed35bb0d-cbc3-a2ab-b58b-3d635beb1f=
39%40scylladb.com</a>.<br />

--------------8F4B7C765D56816EC4CE3277--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 19 Jul 2016 12:44:19 -0700 (PDT)
Raw View
------=_Part_255_294293251.1468957459321
Content-Type: multipart/alternative;
 boundary="----=_Part_256_1318444641.1468957459321"

------=_Part_256_1318444641.1468957459321
Content-Type: text/plain; charset=UTF-8

On Sunday, July 17, 2016 at 6:51:58 AM UTC-4, Bengt Gustafsson wrote:
>
> When it comes to arrays of stateless objects I think there is a fourth
> option worth considering:
>
> 4. arrays of stateless objects take no room in the declared scope, but
> pointer arithmethics and indexing works as if sizeof(T) is 1, (which indeed
> it is).
>
> This allows loops over the array elements and pointer arithmetic and
> similar operations to work as for any type. Of course you can't actually
> access the array elements, but this doesn't matter as there is nothing
> there anyway. I can't see that it would be worse to, say, do this:
>

A stateless object is supposed to be an object you can *access*. The whole
point of defining statelessness as I have is to make such objects behave
like regular objects as much as possible. Passing pointers and references
to stateless subobjects is not *optional*.

Remember the primary use case:

template<typename Alloc>
struct Block
{
  stateless(auto) Alloc a;
};

If I can't do something as simple as pass a pointer/reference to `a`
around, even as a function parameter, why would you do this rather than
make `Alloc` be a base class? You've got to permit the same functionality
as in the base class case, or the whole idea is pointless.

Having "stateless objects" where you can't get a valid pointer to the
object is a non-starter. Better to outright forbid requests which cannot be
fulfilled than to pretend to fulfill those requests, but then tack on a
bunch of conditions on their use.

If you cannot make a stateless array work like a regular array, then just
don't allow them.

On Sunday, July 17, 2016 at 6:59:43 AM UTC-4, Bengt Gustafsson wrote:
>
> Sorry, that got sent before it was complete...
>
> I was aiming to point out that the this pointer when calling the method on
> the scalar s is just as invalid as when calling it for arr[1].
>
> Oh, right now I see that this may cause an aliasing problem if the array
> address range goes outside the surrounding object, and then for instance
> two of those objects are allocated after each other on the heap.
>

That's not really an aliasing problem as a "my pointer isn't valid" problem.


> This brings up an idea I have had in the back of my head for a couple of
> days:
>
> Couldn't it just be demanded from the compiler to guarantee that no two
> objects of the same type have the same address? Here is an example:
>

No. That would mean that `stateless` becomes a *suggestion*, not a
requirement. That's bad. We're trying to *improve* EBO, not take its bad
ideas.

It would also prevent implementations from having null conversions to a
particular stateless subobject (that is, keeping the pointer the same as
the container). And keeping that door open is important for other features
I want to see.

But in any case, if someone uses `stateless`, they should mean it. And if
it can't be stateless, then it should be a hard error. After all, this is
all about being able to control the layout of a type. If your layout
controls are *optional*, why bother?

On Sunday, July 17, 2016 at 8:02:38 AM UTC-4, Bengt Gustafsson wrote:
>
> This also touches on the discussion of inheriting from T to get EBO and
> then having the first NSDM being a T too, which creates an alias situation
> today, which this rule would (potentially) remove.
>

No, it does not create an aliasing situation. Such a type is not standard
layout, and therefore EBO is not required. And [intro.object]/6 makes it
clear that the only legal layouts for such a type are those where the two
subobjects would have different addresses.

So that's not a case we need to be concerned about. I mean, we have to be
concerned about it from the perspective of how it works if you declare one
or both objects to be stateless subobjects. But the old way that works
ought to be fine.

This rule could also be refined to guarantee that there is no aliasing
> between stateless variables and other variables even if they have different
> types:
>

I see no reason to impose this limitation. Permitting two subobjects with
different types to overlap in storage should not be a standardization
problem. [intro.object]/5 explicitly permits it in certain cases, so we can
expand this to others.

The only problem is dealing with two stateless subobjects of the same type.
Or stateless subobjects and non-stateless base classes that have the same
type. Or an annoyingly huge variety of similar cases.

But I think I've found a halfway decent rule that makes this work.

I think we are definitely making progress, but it is still unclear if this
> reasoning leads all the way to a useful proposal. My conclusions are that
> 'stateless' on class and variable levels carry part of the semantic meaning
> and that all four combinations are different:
>

I don't at all agree with your particular combinations, but I am leaning
towards a different distinction. I think that the syntax used on subobject
declarations should be different from what you specify on a type. At this
point in the design, they are diverging enough to be worthy of separate
syntax.

I'm leaning towards calling the subobject declaration `zero_sized`, since
that is what it means: the subobject is zero-sized. Not the type itself,
just the subobject.

Applying `stateless` to a type means that, when it is used as a subobject,
it will be `zero_sized`, but it also means that the type has no identity.
Oh, it still has an address, like any object. But the standard will no
longer guarantee that the address of one instance of that type will be
distinct from any other instance of that type. Also, a `stateless` type
cannot have subobjects that are merely `zero_sized`; they must be types
declared `stateless`. After all, if the containing type has no guaranteed
unique identity, then neither can any type it contains.

But at no time does either one mean that `this` does not exist or that you
can't get pointers to zero-sized subobjects.

--
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/d23eee7f-7969-4ba1-860b-0c372759c5bb%40isocpp.org.

------=_Part_256_1318444641.1468957459321
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Sunday, July 17, 2016 at 6:51:58 AM UTC-4, Bengt Gustaf=
sson 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">Wh=
en it comes to arrays of stateless objects I think there is a fourth option=
 worth considering:<div><br></div><div>4.
 arrays of stateless objects take no room in the declared scope, but=20
pointer arithmethics and indexing works as if sizeof(T) is 1, (which=20
indeed it is).<br><br>This allows loops over the array elements and=20
pointer arithmetic and similar operations to work as for any type. Of=20
course you can&#39;t actually access the array elements, but this doesn&#39=
;t=20
matter as there is nothing there anyway. I can&#39;t see that it would be=
=20
worse to, say, do this:</div></div></blockquote><div><br>A stateless object=
 is supposed to be an object you can <i>access</i>.
 The whole point of defining statelessness as I have is to make=20
such objects behave like regular objects as much as possible. Passing point=
ers and references to stateless subobjects is not <i>optional</i>.<br><br>R=
emember the primary use case:<br><br><div class=3D"prettyprint" style=3D"ba=
ckground-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); borde=
r-style: solid; border-width: 1px; word-wrap: break-word;"><code class=3D"p=
rettyprint"><div class=3D"subprettyprint"><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">template</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">&lt;</span><span style=3D"color: #008;" class=3D"st=
yled-by-prettify">typename</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> </span><span style=3D"color: #606;" class=3D"styled-by-pre=
ttify">Alloc</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">&gt;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=
</span><span style=3D"color: #008;" class=3D"styled-by-prettify">struct</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span =
style=3D"color: #606;" class=3D"styled-by-prettify">Block</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"><br>=C2=A0 stateless</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #00=
8;" class=3D"styled-by-prettify">auto</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #606;" class=3D"styled-by-p=
rettify">Alloc</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> a</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></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><br>If I can&#39;t do something as simple as pass a pointer/reference to=
 `a` around, even as a function parameter, why would you do this rather tha=
n make `Alloc` be a base class? You&#39;ve got to permit the same functiona=
lity as in the base class case, or the whole idea is pointless.<br><br>Havi=
ng
 &quot;stateless objects&quot; where you can&#39;t get a valid pointer to t=
he object=20
is a non-starter. Better to outright forbid requests which cannot be=20
fulfilled than to pretend to fulfill those requests,=20
but then tack on a bunch of conditions on their use.<br><br>If you cannot m=
ake a stateless array work like a regular array, then just don&#39;t allow =
them.<br></div><br>On Sunday, July 17, 2016 at 6:59:43 AM UTC-4, Bengt Gust=
afsson 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">=
Sorry, that got sent before it was complete...<div><br></div><div>I was aim=
ing to point out that the this pointer when calling the method on the scala=
r s is just as invalid as when calling it for arr[1].</div><div><br></div><=
div>Oh, right now I see that this may cause an aliasing problem if the arra=
y address range goes outside the surrounding object, and then for instance =
two of those objects are allocated after each other on the heap.</div></div=
></blockquote><div><br>That&#39;s not really an aliasing problem as a &quot=
;my pointer isn&#39;t valid&quot; problem.<br>=C2=A0</div><blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;"><div dir=3D"ltr"><div>This brings up an idea I =
have had in the back of my head for a couple of days:</div><div><br></div><=
div>Couldn&#39;t it just be demanded from the compiler to guarantee that no=
 two objects of the same type have the same address? Here is an example:</d=
iv></div></blockquote><div><br>No. That would mean that `stateless` becomes=
 a <i>suggestion</i>, not a requirement. That&#39;s bad. We&#39;re trying t=
o <i>improve</i> EBO, not take its bad ideas.<br><br>It would also prevent =
implementations from having null conversions to a particular stateless subo=
bject (that is, keeping the pointer the same as the container). And keeping=
 that door open is important for other features I want to see.<br><br>But i=
n any case, if someone uses `stateless`, they should mean it. And if it can=
&#39;t be stateless, then it should be a hard error. After all, this is all=
 about being able to control the layout of a type. If your layout controls =
are <i>optional</i>, why bother?<br></div><br>On Sunday, July 17, 2016 at 8=
:02:38 AM UTC-4, Bengt Gustafsson wrote:<blockquote class=3D"gmail_quote" s=
tyle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-le=
ft: 1ex;"><div dir=3D"ltr"><div><div><div>This
 also touches on the discussion of inheriting from T to get EBO and then
 having the first NSDM being a T too, which creates an alias situation=20
today, which this rule would (potentially) remove.</div></div></div></div><=
/blockquote><div><br>No,
 it does not create an aliasing situation. Such a type is not standard=20
layout, and therefore EBO is not required. And [intro.object]/6 makes it
 clear that the only legal layouts for such a type are those where the two =
subobjects would have different addresses.<br><br>So that&#39;s not a case =
we need to be concerned about. I mean, we have to be concerned about it fro=
m the perspective of how it works if you declare one or both objects to be =
stateless subobjects. But the old way that works ought to be fine.<br><br><=
/div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8e=
x;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><di=
v><div>This
 rule could also be refined to guarantee that there is no aliasing=20
between stateless variables and other variables even if they have=20
different types:</div></div></div></div></blockquote><br>I see no=20
reason to impose this limitation. Permitting two subobjects with different =
types to overlap
 in storage should not be a standardization problem. [intro.object]/5=20
explicitly permits it in certain cases, so we can expand this to others.<br=
><br>The only problem is dealing with two stateless subobjects of the same =
type. Or stateless subobjects and non-stateless base classes that have the =
same type. Or an annoyingly huge variety of similar cases.<br><br>But I thi=
nk I&#39;ve found a halfway decent rule that makes this work.<br><br><block=
quote style=3D"margin: 0px 0px 0px 0.8ex; border-left: 1px solid rgb(204, 2=
04, 204); padding-left: 1ex;" class=3D"gmail_quote"><div>I
 think we are definitely making progress, but it is still unclear if=20
this reasoning leads all the way to a useful proposal. My conclusions=20
are that &#39;stateless&#39; on class and variable levels carry part of the=
=20
semantic meaning and that all four combinations are different:</div></block=
quote><br>I
 don&#39;t at all agree with your particular combinations, but I am leaning=
=20
towards a different distinction. I think that the syntax used on=20
subobject declarations should be different from what you specify on a=20
type. At this point in the design, they are diverging enough to be=20
worthy of separate syntax.<br><br>I&#39;m leaning towards calling the=20
subobject declaration `zero_sized`, since that is what it means: the=20
subobject is zero-sized. Not the type itself, just the subobject.<br><br>Ap=
plying
 `stateless` to a type means that, when it is used as a subobject, it=20
will be `zero_sized`, but it also means that the type has no identity.=20
Oh, it still has an address, like any object. But the standard will no=20
longer guarantee that the address of one instance of that type will be=20
distinct from any other instance of that type. Also, a `stateless` type=20
cannot have subobjects that are merely `zero_sized`; they must be types=20
declared `stateless`. After all, if the containing type has no=20
guaranteed unique identity, then neither can any type it contains.<br><br>B=
ut at no time does either one mean that `this` does not exist or that you c=
an&#39;t get pointers to zero-sized subobjects.<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/d23eee7f-7969-4ba1-860b-0c372759c5bb%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/d23eee7f-7969-4ba1-860b-0c372759c5bb=
%40isocpp.org</a>.<br />

------=_Part_256_1318444641.1468957459321--

------=_Part_255_294293251.1468957459321--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 19 Jul 2016 16:35:43 -0700 (PDT)
Raw View
------=_Part_5679_467869714.1468971343841
Content-Type: multipart/alternative;
 boundary="----=_Part_5680_176827862.1468971343841"

------=_Part_5680_176827862.1468971343841
Content-Type: text/plain; charset=UTF-8

Yet another revision.

This one puts forth my preferred solution to the so-called unique identity
problem. Namely, finding a good rule to forbid cases where stateless
subobjects would lose identity, but allowing types declared stateless to
have identity. This also means that stateless types cannot have subobjects
that are not themselves declared stateless.

The new version also recognizes something I hadn't realized about
`is_empty`. Namely that being empty by that definition does not mean that
the type's size is 1. An `is_empty` type does not have to be standard
layout.

As such, I've changed the wording to not talk about empty types with
stateless subobjects. Instead, I define a new concept: possibly stateless
types (PSTs), which is a type that satisfies `is_empty` and
`is_standard_layout`, since only these types are required by the standard
to have no non-zero-sized subobjects.

Furthermore, I've been thinking a lot about making a syntactic change.
Since `stateless` as it applies to types now has a stronger meaning, it
occurs to me that a stateless type is something rather different from a
stateless subobject. Stateless types imply possible loss of identity, while
stateless subobjects do not. I've also looked up some rules on how base
class layouts are treated, and I noticed that the standard had quite a few
provisions for "zero sized" subobjects. Granted, only base class
subobjects, but that can be changed.

So I'm thinking that it would be best to change the per-subobject
declaration to `zero_sized` or something like that. This makes it clear
that the subobject takes up no size in the container's layout. `stateless`
would still be used on types, since that represents something much
stronger: a willingness to lose identity and so forth.

--
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/02a8825f-ed6b-432d-94cb-ded96a7ac4cd%40isocpp.org.

------=_Part_5680_176827862.1468971343841
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Yet another revision.<br><br>This one puts forth my prefer=
red solution to the so-called unique identity problem. Namely, finding a go=
od rule to forbid cases where stateless subobjects would lose identity, but=
 allowing types declared stateless to have identity. This also means that s=
tateless types cannot have subobjects that are not themselves declared stat=
eless.<br><br>The new version also recognizes something I hadn&#39;t realiz=
ed about `is_empty`. Namely that being empty by that definition does not me=
an that the type&#39;s size is 1. An `is_empty` type does not have to be st=
andard layout.<br><br>As such, I&#39;ve changed the wording to not talk abo=
ut empty types with stateless subobjects. Instead, I define a new concept: =
possibly stateless types (PSTs), which is a type that satisfies `is_empty` =
and `is_standard_layout`, since only these types are required by the standa=
rd to have no non-zero-sized subobjects.<br><br>Furthermore, I&#39;ve been =
thinking a lot about making a syntactic change. Since `stateless` as it app=
lies to types now has a stronger meaning, it occurs to me that a stateless =
type is something rather different from a stateless subobject. Stateless ty=
pes imply possible loss of identity, while stateless subobjects do not. I&#=
39;ve also looked up some rules on how base class layouts are treated, and =
I noticed that the standard had quite a few provisions for &quot;zero sized=
&quot; subobjects. Granted, only base class subobjects, but that can be cha=
nged.<br><br>So I&#39;m thinking that it would be best to change the per-su=
bobject declaration to `zero_sized` or something like that. This makes it c=
lear that the subobject takes up no size in the container&#39;s layout. `st=
ateless` would still be used on types, since that represents something much=
 stronger: a willingness to lose identity and so forth.<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/02a8825f-ed6b-432d-94cb-ded96a7ac4cd%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/02a8825f-ed6b-432d-94cb-ded96a7ac4cd=
%40isocpp.org</a>.<br />

------=_Part_5680_176827862.1468971343841--

------=_Part_5679_467869714.1468971343841
Content-Type: text/html; charset=UTF-8; name="Stateless Subobjects.html"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename="Stateless Subobjects.html"
X-Attachment-Id: 32f7b5fd-4cab-4bf3-b727-9d335364be7b
Content-ID: <32f7b5fd-4cab-4bf3-b727-9d335364be7b>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.=
w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns=3D"http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8" =
/>
  <meta http-equiv=3D"Content-Style-Type" content=3D"text/css" />
  <meta name=3D"generator" content=3D"pandoc" />
  <meta name=3D"date" content=3D"2016-07-19" />
  <title>Stateless Subobjects and Types, pre-release v4</title>
  <style type=3D"text/css">code{white-space: pre;}</style>
</head>
<body>
<div id=3D"header">
<h1 class=3D"title">Stateless Subobjects and Types, pre-release v4</h1>
<h3 class=3D"date">July 19, 2016</h3>
</div>
<div id=3D"TOC">
<ul>
<li><a href=3D"#motivation">Motivation and Scope</a></li>
<li><a href=3D"#design">Design</a><ul>
<li><a href=3D"#possibly-stateless-types">Possibly-stateless types</a></li>
<li><a href=3D"#stateless-subobojects">Stateless subobojects</a></li>
<li><a href=3D"#stateless_behavior">Stateless behavior</a></li>
<li><a href=3D"#stateless-types">Stateless types</a></li>
<li><a href=3D"#stateless-anonymous-types">Stateless anonymous types</a></l=
i>
<li><a href=3D"#unique_rule">Unique identity rule</a></li>
</ul></li>
<li><a href=3D"#design-rationale">Design rationale</a><ul>
<li><a href=3D"#memory-locations">Memory locations</a></li>
<li><a href=3D"#stateless-arrays">Stateless arrays</a></li>
<li><a href=3D"#trivial-copyability">Trivial copyability</a></li>
<li><a href=3D"#offsetof">offsetof</a></li>
<li><a href=3D"#identity">Unique identity problem</a></li>
</ul></li>
<li><a href=3D"#potential-issues">Potential issues</a><ul>
<li><a href=3D"#the-unknown">The Unknown</a></li>
</ul></li>
<li><a href=3D"#alternative-designs-explored">Alternative Designs Explored<=
/a><ul>
<li><a href=3D"#magic-standard-library-wrapper-type">Magic standard library=
 wrapper type</a></li>
<li><a href=3D"#stateless-by-type-declaration">Stateless by type declaratio=
n</a></li>
</ul></li>
<li><a href=3D"#changelist">Changelist</a><ul>
<li><a href=3D"#from-pre-release-v3">From pre-release v3:</a></li>
<li><a href=3D"#from-pre-release-v2">From pre-release v2:</a></li>
<li><a href=3D"#from-pre-release-v1">From pre-release v1:</a></li>
</ul></li>
<li><a href=3D"#standard-notes">Standard notes:</a></li>
<li><a href=3D"#acknowledgments">Acknowledgments</a></li>
</ul>
</div>
<p>This proposal specifies the ability to declare member and base class sub=
objects which do not take up space in the objects they are contained within=
.. It also allows the user to define classes which will always be used in su=
ch a fashion.</p>
<h1 id=3D"motivation">Motivation and Scope</h1>
<p>An object is stateless, conceptually speaking, if it has no non-static d=
ata members. As such, the state of any particular instance is no different =
from another. Because of this, there is no conceptual reason why a stateles=
s object needs to have a region of storage associated with it.</p>
<p>In C++, a class would be stateless if it has no non-static data members =
(NSDMs) and all of its base classes likewise are stateless as well. <code>i=
s_empty_v</code> qualifies as a useful test, but technically other classes =
could qualify as well (those with virtual members/base classes).</p>
<p>There are many times when a user wants to use a class that the user prov=
ides, but the class may or may not be logically stateless. If it is statele=
ss, then it would be best if the class which uses it would not grow in size=
 simply due to the presence of the stateless subobject. After all, a concep=
tually stateless object does not need to take up space to do its job.</p>
<p>To avoid this, users will frequently use standard layout rules and the e=
mpty base optimization to allow them to have access to a stateless subobjec=
t:</p>
<pre><code>template&lt;typename Alloc&gt;
struct DataBlock : public Alloc
{
};</code></pre>
<p>In this case, if <code>Alloc</code> is empty, then so long as <code>Data=
Block</code> follows standard layout rules, the user is guaranteed that <co=
de>DataBlock</code> is no larger than it would have been if <code>Alloc</co=
de> were not empty. Even if it does not follow standard layout, the compile=
r is free to optimize the empty base <code>Alloc</code> away.</p>
<p>There are of course problems with such a use. If <code>Alloc</code> is n=
ot empty (and <code>DataBlock</code> does not require that it is), and <cod=
e>Alloc</code> declares a virtual function, it is possible that <code>DataB=
lock&lt;Alloc&gt;</code> will accidentally override that virtual function. =
Or not quite override it and cause a compile error. Whereas if <code>Alloc<=
/code> were a non-static data member, this could easily be avoided.</p>
<p>Equally importantly, this use of <code>Alloc</code> is simply not how a =
user would naturally write this class. Inheritance is supposed to model an =
&quot;is a&quot; relationship. Yet conceptually, <code>DataBlock</code> is =
not an <code>Alloc</code>; it <em>has</em> an <code>Alloc</code>. <code>Dat=
aBlock</code> uses inheritance, not to model a relationship, but as an opti=
mization tool, to keep the class from growing unnecessarily.</p>
<p>The intent of this proposal is to permit, among other things, classes li=
ke <code>DataBlock</code> to declare <code>Alloc</code> as a non-static dat=
a member. And if <code>Alloc</code> is empty, then <code>DataBlock</code> c=
an use syntax to make the <code>Alloc</code> NSDM take up no space in <code=
>DataBlock</code>'s layout.</p>
<p>This would also be recursive, so that if <code>Alloc</code> had no NSDMs=
, and <code>DataBlock&lt;Alloc&gt;</code> had no NSDMs besides the <code>Al=
loc</code> member, then <code>DataBlock&lt;Alloc&gt;</code> would also be c=
onsidered an empty type. And therefore, some other type could use it in a s=
tateless fashion.</p>
<h1 id=3D"design">Design</h1>
<p>We define two concepts: stateless subobjects and stateless classes. A st=
ateless class is really just shorthand for the former; it declares that ins=
tances of the class can only be created as stateless subobjects of some oth=
er type.</p>
<p>Note: The following syntax is entirely preliminary. This proposal is not=
 wedded to the idea of introducing a new keyword or somesuch. This syntax i=
s here simply for the sake of understanding how the functionality should ge=
nerally be specified. The eventual syntax could be a contextual keyword lik=
e <code>final</code> and <code>override</code>, or it could be something el=
se.</p>
<h2 id=3D"possibly-stateless-types">Possibly-stateless types</h2>
<p>A possibly-stateless type (PST) is a type which could be used in a state=
less way. This is defined as any class type for which both <code>std::is_em=
pty</code> and <code>std::is_standard_layout</code> apply. The definition o=
f <code>is_empty</code> is expanded by the <a href=3D"#stateless_behavior">=
behavior of stateless subobjects</a>.</p>
<p>The standard library will need a traits class <code>is_possibly_stateles=
s</code> to detect if a type is possibly stateless.</p>
<h2 id=3D"stateless-subobojects">Stateless subobojects</h2>
<p>A non-static data member subobject of a type can be declared stateless w=
ith the following syntax:</p>
<pre><code>struct Data
{
    stateless Type val;
};</code></pre>
<p>A base class subobject of a type can be declared stateless with the foll=
owing syntax:</p>
<pre><code>struct Data : public stateless Type
{
    ...
};</code></pre>
<p>For these declarations to be well-formed, <code>Type</code> must be a PS=
T.</p>
<p><code>stateless</code> cannot be applied to:</p>
<ul>
<li>Members of a <code>union</code> class</li>
<li>base classes that use <code>virtual</code> inheritance</li>
<li>Member subobjects that are arrayed</li>
<li>Variables that are not declared as non-static data members</li>
</ul>
<p>The stateless property can be conditional, based on a compile-time condi=
tion like <code>noexcept</code>. This is done as follows:</p>
<pre><code>template&lt;typename Alloc&gt;
struct DataBlock
{
    stateless(is_possibly_stateless_v&lt;Alloc&gt;) Alloc a;
};</code></pre>
<p>In this case, <code>a</code> will be a stateless member only if its type=
 is a PST. If the condition is false, then it is as if the stateless proper=
ty were not applied to the subobject.</p>
<p>To facilitate common use patterns, the <code>stateless(auto)</code> synt=
ax for subobjects shall be equivalent to <code>stateless(std::is_possibly_s=
tateless_v&lt;T&gt;)</code>, where <code>T</code> is the type of the subobj=
ect being declared.</p>
<p>Classes which contain stateless subobjects, directly or indirectly, are =
subject to the <a href=3D"#unique_rule">Unique Identity Rule</a>. Class dec=
larations that violate the unique identity rule are il-formed.</p>
<h2 id=3D"stateless_behavior">Stateless behavior</h2>
<p>Stateless subobjects have no effect on the layout or size of their conta=
ining object. Similarly, the rules for standard layout types ignore the pre=
sence of any stateless subobjects (a class can be standard layout with publ=
ic stateless members and private non-stateless members). And thus, two clas=
ses can be layout compatible even if they differ by the presence of statele=
ss subobjects.</p>
<p>Stateless subobjects otherwise have the same effects on their containing=
 types as regular subobjects do. For example, a stateless subobject can cau=
se its container to not be trivially copyable, if it has a non-trivial copy=
 constructor (even though the object by definition has no state to copy).</=
p>
<p>The definition of &quot;empty class&quot; (per <code>std::is_empty</code=
>) must now be expanded. The rules for an empty class are:</p>
<ul>
<li>Non-union class.</li>
<li>No virtual functions.</li>
<li>No virtual base classes.</li>
<li>No non-empty base classes (stateless base subobjects are, by definition=
, empty).</li>
<li>No non-stateless NSDMs.</li>
</ul>
<p>In all other ways, except where detailed below, a stateless subobject wo=
rks identically to a non-stateless one. Stateless subobjects are initialize=
d and destroyed just as if they were not stateless. Stateless subobjects un=
dergo copy and move construction and assignment along with all other subobj=
ects (though they will likely not be doing much). In particular, stateless =
subobjects are still members/base classes of the types that contain them, s=
o aggregate initialization of members (and bases) will still have to take t=
hem into account:</p>
<pre><code>struct foo {};

struct aggregate
{
  stateless foo f;
  int b;
};

//It may have no state, but `f` must still be initialized.
aggregate agg =3D {{}, 4};</code></pre>
<p>Note that the alignment of a stateless subobject will still impact the a=
lignment of the containing class. A <code>stateless</code> member declarati=
on can include an <code>alignas</code> specifier as well.</p>
<h2 id=3D"stateless-types">Stateless types</h2>
<p>The stateless property can be applied to (non-union) types as well:</p>
<pre><code>stateless class ClassName : BaseClasses
{
    ...
};</code></pre>
<p>The <code>stateless</code> keyword must be consistently associated with =
any forward declarations for stateless types.</p>
<pre><code>class ClassName;  //Not a stateless type.

stateless class ClassName  //Compiler error: you told me it wasn&#39;t stat=
eless before.
{
};</code></pre>
<p>And vice-versa.</p>
<p>A stateless class definition is ill-formed if the class is not a PST. Ho=
wever, a stateless class definition is also il-formed if it has any subobje=
cts that are not themselves of stateless types.</p>
<p>The size of a stateless class is not affected by being stateless. Theref=
ore, the size of a stateless class shall be no different from the size of a=
ny other PST class.</p>
<p>The statelessness of a type can be conditional, just like subobjects:</p=
>
<pre><code>template&lt;typename T&gt;
stateless(is_stateless_v&lt;T&gt;) struct Foo : public T {};</code></pre>
<p>Here, <code>Foo</code> may or may not be stateless, depending on whether=
 <code>T</code> is a stateless type. If the constant expression evaluates t=
o <code>false</code>, then the class is not stateless.</p>
<p>To make certain conditions easier, there will be the <code>stateless(aut=
o)</code> syntax. When applied to a class declaration, <code>stateless(auto=
)</code> will cause the class to be stateless if all of the subobjects are =
of stateless types.</p>
<p>When a stateless class is used to create an object in a way that cannot =
have <code>stateless</code> applied to it, then the code behaves just as it=
 would if the class did not have the <code>stateless</code> keyword. Theref=
ore, you can heap allocate arrays of stateless classes, and they will funct=
ion just like any heap allocated array of PST classes. You can declare an a=
utomatic or global variable of a stateless type, and it will behave as any =
PST class (note: implementations are free to optimize such objects to take =
up no stack space if possible, but they are not required to do so).</p>
<p>However, when a stateless class is used to declare a direct subobject of=
 another type, that subobject will be implicitly stateless. It is perfectly=
 valid to explicitly specify <code>stateless</code> on a member/base class =
of a stateless type as well. If the conditions on the two <code>stateless</=
code> properties do not agree (one resolves to true and the other false), t=
hen the program is il-formed.<a href=3D"#fn1" class=3D"footnoteRef" id=3D"f=
nref1"><sup>1</sup></a></p>
<p>Stateless subobjects created through stateless classes are exempt from t=
he <a href=3D"#unique_rule">unique identity rule</a>.</p>
<p>Declaring an array of a stateless type as an NSDM is forbidden. Stateles=
s types may not be used as members of a union.</p>
<p>The standard library will need a traits class to detect if a type is sta=
teless, since being <code>stateless</code> does have other properties.</p>
<h2 id=3D"stateless-anonymous-types">Stateless anonymous types</h2>
<p>Statelessness can be applied to anonymous types as well:</p>
<pre><code>stateless(auto) struct
{
    Data d;
} varName;</code></pre>
<p>The <code>stateless</code> property applies to the struct declaration, n=
ot the variable. As such, <code>decltype(varName)</code> will be a stateles=
s type if <code>Data</code> is a stateless type. Such declarations can only=
 be made as non-static data members.</p>
<h2 id=3D"unique_rule">Unique identity rule</h2>
<p>Any class which contains a subobject which is stateless (directly or ind=
irectly) is subject to the unique identity rule. The goal of this rule is t=
o ensure that each object within a struct has <a href=3D"#identity">unique =
identity</a> while fulfilling the layout needs of being <code>stateless</co=
de>. This rule is as follows.</p>
<p>For every subobject, recursively, of a class <code>T</code>, if that sub=
object is declared <code>stateless</code>, and that subobject is not of a <=
code>stateless</code> type, then look through <code>T</code>'s subobjects, =
recursively. If there is another subobject of that type, and that subobject=
 is created from a different subobject <em>declaration</em>, then <code>T</=
code> violates the unique identity rule.</p>
<p>Note that &quot;different subobject declaration&quot; means the followin=
g:</p>
<pre><code>struct empty {};
struct holder { stateless empty e; };

struct data
{
    holder h1;
    holder h2;
};</code></pre>
<p><code>h2.e</code> does not cause a violation of the unique identity rule=
.. The reason being that <code>h1.e</code> and <code>h2.e</code> both come f=
rom the same declaration: the definition of <code>holder</code>.</p>
<p>By contrast, these would be illegal:</p>
<pre><code>struct data2
{
    holder h1;
    empty e2; //Same type as `h1::e`, but different declaration.
};

struct data2a
{
    holder h1;
    stateless holder h2; //Same type as `h1`, but different declaration.
};</code></pre>
<p>Do note that the identity rule works even for derived classes and arrays=
 of types that contain stateless subobjects:</p>
<pre><code>struct data3 : public holder
{
    holder h2;
    holder hs[40];
};</code></pre>
<p>This works because of standard layout rules. Or rather, because <code>da=
ta3</code> is <em>not</em> standard layout. Because of that, <code>data3::h=
older</code> and <code>data::h2</code> must have distinct addresses. And th=
erefore, their stateless subobjects will as well.</p>
<p>This does forbid many cases that theoretically could work. It may be pos=
sible to come up with more complex forms of this rule that allow stateless =
subobjects to be used in more places. But with added complexity comes the c=
hance to get something wrong.</p>
<h1 id=3D"design-rationale">Design rationale</h1>
<p>A number of restrictions on the use of stateless types come from impleme=
ntation restrictions or the needs of basic C++ assumptions about types. Thi=
s section goes into detail about some of the rationales for the design deci=
sions, as well as alternatives that were discarded.</p>
<h2 id=3D"memory-locations">Memory locations</h2>
<p>In C++ as it currently stands, every object needs to have a memory locat=
ion. And in most cases two separate objects of unrelated types cannot have =
the <em>same</em> memory location.</p>
<p>Stateless subobojects effectively have to be able to break this rule. Th=
e memory location of a stateless subobject is more or less irrelevant. Sinc=
e the type is stateless, there is no independent state to access. So one in=
stance is functionally no different from another (pursuant to the <a href=
=3D"#identity">unique identity rule</a>).</p>
<p>As such, the general idea is that a stateless subobject could have any a=
ddress within the storage of the object which contains it. This means that =
a stateless subobject can have the same address as any other subobject in i=
ts containing object's type. The standard has rules for zero-sized subobjec=
ts ([intro.object]/5-6). At present, only base classes can qualify ([class]=
/4), but we can build on the existing infrastructure for stateless subobjec=
ts.</p>
<p>This is not really an implementation problem, since stateless suboboject=
s by their very nature have no state to access. As such, the specific addre=
ss of their <code>this</code> pointer is irrelevant. What we need, standard=
-wise, is to modify the rules for accessing objects and aliasing to allow a=
 stateless subobject to have the same address as <em>any</em> other object.=
 Because stateless objects have no value to access, we may not even need to=
 change [basic.lval]/10.</p>
<p>The address of a stateless subobject can be any address within the stora=
ge of the object that contains it. The standard need not specify exactly wh=
ich address.</p>
<p>Implementation-wise, the difficulty will be in changing how types are la=
id out. That is, modifying ABIs to allow member subobjects that have no siz=
e and enforcing EBO even when it might otherwise have been forbidden.</p>
<p>The behavior of the <em>user</em> converting pointers/references between=
 two unrelated stateless subobjects should still be undefined. We just need=
 rules to allow stateless subobjects to be assigned a memory location at th=
e discretion of the compiler, which may not be unique from other unrelated =
objects.</p>
<h2 id=3D"stateless-arrays">Stateless arrays</h2>
<p>This design expressly forbids the declaration of stateless member subobj=
ects that are arrayed. The reason for this has to do with pointer arithmeti=
c.</p>
<p>In C++, the following should be perfectly valid for any type <code>T</co=
de>, regarldess of where the array of <code>T</code> is declared:</p>
<pre><code>T t[5];
T *first =3D &amp;t[0];
T *last =3D first + 5;
assert(sizeof(T) * 5 =3D=3D last - first);</code></pre>
<p>The whole point of a stateless subobject is that it does not take up spa=
ce within another type. If the array above were a member of another type, t=
his code still ought to work. But, since <code>sizeof(T)</code> is non-zero=
, that means that those values have to take up space somewhere. Each pointe=
r has to be valid.</p>
<p>Under non-array conditions, the pointer to a stateless subobject could a=
lways have the same address as its container (recursively, to the last non-=
stateless container). Adding 1 to any such pointer will still be a valid ad=
dress; this is required because any object can be considered an array of 1 =
value ([expr.add]/4). If the containing class is an empty class with a size=
 of 1, then adding one to a stateless member's pointer is no less valid tha=
n adding 1 to the container's address.</p>
<p>When dealing with an array, this is not necessarily the case. If the sta=
teless array has a count larger than 1, and it is contained in an empty cla=
ss, there is no guarantee that adding a number larger than 1 will result in=
 a valid address for the purposes of iteration.</p>
<p>Several alternatives were considered:</p>
<ol style=3D"list-style-type: decimal">
<li><p>Declare that <code>sizeof</code> for stateless subobjects is zero. I=
 am not nearly familiar enough with the C++ standard to know the level of h=
orrors that this would unleash, but I can imagine that it's very bad. It wo=
uld also make it impossible to have a distinction between stateless subobje=
cts and stateless types, as the <code>sizeof</code> can be applied to a poi=
nter to the object, which cannot know if the object it points to is statele=
ss.</p></li>
<li><p>Declare that stateless subobjects which are arrayed will still take =
up space as though they were not declared <code>stateless</code>.</p></li>
<li><p>Forbid declaring arrays of stateless subobjects altogether.</p></li>
</ol>
<p>Option 1 is probably out due to various potential issues. #2 seems tempt=
ing, but it makes the use of <code>stateless T arr[4];</code> something of =
a lie. Earlier designs used #3, then switched to #2. But the current design=
 goes back to #3 for an important reason.</p>
<p>In the current design, it is the <em>use</em> of a type which is statele=
ss. Types can be declared stateless as well, but this really only means tha=
t all uses of them to declare objects will implicitly be stateless. So this=
 restricts how the type may be used, but not the semantics of it.</p>
<p>Because statelessness can be applied to any PST class at its point of us=
e, if a user wants to be able to use an PST class in a non-stateless way, t=
hen they simply do not declare the class to be stateless.</p>
<p>And therefore, if you declare a class to be stateless, you truly intend =
for it to only be used as a subobject of another type. This would be useful=
 for a CRTP base class, for example, where it is a logical error to create =
an object of the class which is not a base class.</p>
<h2 id=3D"trivial-copyability">Trivial copyability</h2>
<p>Trivial copyability is another area that can be problematic with statele=
ss subobjects. We explicitly forbid trivial copying into a base class subob=
ject of another class ([basic.types]/2).</p>
<p>Similarly, we must explicitly forbid trivial copying into stateless subo=
bojects. Trivial copying <em>from</em> a stateless subobject should be OK. =
Though this is only &quot;OK&quot; in the sense that the program is not ill=
-formed or that there us undefined behavior. The value copied is undefined,=
 but that doesn't matter, since you could only ever use that value to initi=
alize a type that is layout compatible with an PST class. Namely, another P=
ST class. And PST classes have no value.</p>
<h2 id=3D"offsetof">offsetof</h2>
<p><code>offsetof</code> will obviously not be affected by stateless subobj=
ect members of another type. However, if <code>offsetof</code> is applied t=
o a stateless subobject, what is the result?</p>
<p>I would suggest that this either be undefined or 0.</p>
<h2 id=3D"identity">Unique identity problem</h2>
<p>A non-virtual type with no data members or base class data members is em=
pty of valid data. It has no real value representation. But under current C=
++ rules, it does have one important piece of state: itself.</p>
<p>The present rules of C++ allow a number of cases where the addresses of =
two object instances are equal. This usually involves subobjects: base clas=
ses can have the same address as the derived class. The first member subobj=
ect often has the address of the containing class. And for standard layout,=
 empty base classes will have the same address as the first member, which w=
ill have the same address as the containing class.</p>
<p>Despite all of this, there is one inviolate rule with subobject layout: =
for any two distinct objects of the same dynamic type <code>T</code>, they =
will have <em>different addresses</em>. Because of this rule, a type which =
is possibly stateless can grant itself state by using its <code>this</code>=
 pointer as a unique identifier to access external state.</p>
<p>As such, blindly applying <code>stateless</code> to any PST could have u=
npleasant consequences. The purpose of the <a href=3D"#unique_rule">unique =
identity rule</a> is to avoid situations where two such member subobjects c=
ould have the same address.</p>
<p>Various alternatives were considered to solve this problem.</p>
<h3 id=3D"ignore-the-problem">Ignore the problem</h3>
<p>One solution considered was to just ignore the problem. The scope of the=
 problem is such that it would only happen if:</p>
<ol style=3D"list-style-type: decimal">
<li><p>The user has created a PST that gains state state through its object=
 identity.</p></li>
<li><p>The user (or another user) uses this type as a stateless subobject.<=
/p></li>
<li><p>The user (or another user) uses this type as a stateless subobject m=
ore than once in the same object.</p></li>
</ol>
<p>Users who do #1 can defend themselves against #2 simply by declaring tha=
t the type has an NSDM of type <code>char</code>. Alternatively, we can def=
ine special syntax to allow users to actively prevent a PST from being used=
 as a stateless subobject.</p>
<h3 id=3D"there-is-no-problem">There is no problem</h3>
<p>Another solution examined was to redefine the problem. It only occurs wh=
en two or more stateless subobjects of the same type can alias each other w=
ithin the same containing object. So we can simply declare that, when that =
happens, the objects are <em>not distinct objects</em>. One is an alias for=
 the other.</p>
<p>As such, we have identity only of the ultimate non-stateless containing =
subobject. If the user expects (given the above example) <code>multiple::ns=
1</code> and <code>multiple::ns2</code> to be different objects, then the u=
ser is simply wrong to think so.</p>
<p>This sounds like ignoring the problem, but it really is different. In th=
e previous suggestion, it's a corner case. With this suggestion, we concept=
ually re-evaluate what it means to declare that a subobject is stateless. T=
hat being stateless means that the object shares its identity shall effecti=
vely lose its identity among any other subobjects of its own type within th=
e same non-stateless containing object.</p>
<p>That is, rather than declaring it to be an unfortunate bug, we embrace i=
t as a feature. As such, we <em>actively forbid</em> implementations from a=
llowing different stateless instances at the same level from having differe=
nt addresses. <code>multiple::ns1</code> <em>must</em> have the same addres=
s as <code>multiple::ns2</code>.</p>
<p>This also means that there is only one such object. This creates an inte=
resting problem with object lifetime and construction/destruction calls. In=
deed, any per-member compiler-generation function call.</p>
<p>On the one hand, if there is only one such object, then there should onl=
y be one constructor and one destructor call. But there are two member vari=
ables, and having only one call would be weird. Indeed, the two objects cou=
ld be subobjects of different stateless subobjects.</p>
<p>What's worse is that, if the user declares a copy constructor or assignm=
ent operator, they will have to list both objects in their member initializ=
er. If they declare an assignment operator, they have to list both objects.=
</p>
<p>So the only logical alternative here is that you <em>have</em> to call t=
he constructor multiple times. In which case, the object model has to chang=
e.</p>
<p>In order for stateless subobjects of any kind to work, we declare that m=
any objects of different types live in the same region of storage. In order=
 for two stateless subobjects of the same type to live in the same region o=
f storage, we have to declare that, since they have no value representation=
, then a memory location can conceptually hold any number of stateless subo=
bjects of any type. Even if they are the same type.</p>
<p>As such, constructing one member subobject begins its lifetime. Construc=
ting a second begins its lifetime. This leaves you with two objects of the =
same type in the same location of memory.</p>
<h3 id=3D"only-stateless-types-can-be-stateless-subobjects">Only stateless =
types can be stateless subobjects</h3>
<p>With this solution, we make the assumption that, if a user declares that=
 a type is <code>stateless</code>, then they are making a strong claim abou=
t this type. Namely that losing identity is perfectly valid, that it is rea=
sonable for two objects of the same type to have the same address and live =
in the same memory.</p>
<p>So we solve the problem by only permitting stateless subobjects of types=
 that are themselves declared stateless. That way, we know that the user ex=
pects such types to alias. This also means that stateless types can only ha=
ve subobjects of other stateless types (lest they be able to lose identity =
as well).</p>
<p>This solves the unique identity problem by forcing the user to explicitl=
y specify when it is OK to lose unique identity. However, it fails to solve=
 the general problem of people using EBO as a means for having a stateless =
subobject. They will continue to do so, as the set of <code>stateless</code=
> declared objects will always be smaller than the set of PST types that qu=
alify for EBO.</p>
<h3 id=3D"explicitly-forbid-the-problem-cases">Explicitly forbid the proble=
m cases</h3>
<p>The unique identity problem arises because two stateless subobjects of t=
he same type exist within the same containing type. So we can simply forbid=
 that. This is a special case rule, very similar to the one that prevents t=
ypes from being standard layout if their first NSDM is the same type as one=
 of their empty base classes.</p>
<p>We declare that an object which has a stateless subobject that can alias=
 with another instance of that type is il-formed. This would be recursive, =
up the subobject containment hierarchy. That's the general idea, but the cu=
rrent rule takes note of the fact that a stateless object cannot alias with=
 other objects of its type if it is contained in the exact same object decl=
aration.</p>
<h3 id=3D"only-stateless-types-can-lose-identity">Only stateless types can =
lose identity</h3>
<p>This is effectively a combination of the prior two ideas ideas. The desi=
gn in this paper uses this solution, as defined by the <a href=3D"#unique_r=
ule">unique identity rule</a>.</p>
<p>For all PST-but-not-stateless types, we apply a rule that forbids possib=
le unique identity violations. However, if the type is declared <code>state=
less</code>, then we know that the writer of the type has deliberately chos=
en to accept that the type lacks identity, so we permit them to be used wit=
hout restriction.</p>
<p>The current unique identity rule is quite conservative, leaving out situ=
ations where stateless subobjects cannot alias:</p>
<pre><code>struct empty {};
struct alpha {stateless empty e;};
struct beta {stateless empty e;};

struct first
{
    alpha a;
    alpha b;    //Legal
    beta c;     //Not legal.
};</code></pre>
<h1 id=3D"potential-issues">Potential issues</h1>
<h2 id=3D"the-unknown">The Unknown</h2>
<p>One of the most difficult aspects of dealing with any form of stateless =
type system is that it represents something that is very new and very compl=
icated for C++ to deal with. As such, the wording for this needs to be quit=
e precise and comprehensive, lest we introduce subtle bugs into the standar=
d.</p>
<p>A good spec doctor needs to be involved with the standardization of this=
 feature.</p>
<h1 id=3D"alternative-designs-explored">Alternative Designs Explored</h1>
<p>There has been many alternatives towards achieving the same ends. Every =
such alternative has to deal with 2 fundamental rules of the C++ object mod=
el:</p>
<ol style=3D"list-style-type: decimal">
<li>Objects are defined by a region of storage.</li>
<li>Two different object instances have different regions of storage.</li>
</ol>
<p>This current proposal is designed to avoid changes to rule #1. Stateless=
 subobjects in this proposal still have a non-zero size. Instead, changes t=
o rule #2 are made to permit such subobjects to be able to not disturb the =
layout of their container.</p>
<p>Other alternatives take a different approach to dealing with these rules=
..</p>
<h2 id=3D"magic-standard-library-wrapper-type">Magic standard library wrapp=
er type</h2>
<p><a href=3D"https://groups.google.com/a/isocpp.org/d/msg/std-proposals/sA=
dqngl8pew/xCjHCLpuAAAJ">This idea</a> is focused on just the specific case =
of having empty classes potentially take up no space in their containing cl=
asses.</p>
<p>It would essentially declare a standard library type that is, in the con=
text of this proposal, something like this:</p>
<pre><code>template&lt;typename T&gt;
stateless(auto) struct allow_zero_size : public T {...};</code></pre>
<p>It is a wrapper which, when used as an NSDM, will not take up any space =
in its containing object if the given type is empty. And if it is not, then=
 it will.</p>
<p>The theoretical idea behind this is that it doesn't require new syntax. =
And in that proposal, <code>allow_zero_size</code> would not be forbidden f=
rom being in arrays or any of the other forbearances that this proposal for=
bids stateless types from.</p>
<p>This makes the behavior of such a type rather more difficult to specify.=
 The standard would still need to have changes to allow subobojects which t=
ake up no space to work, since users have to be able to get pointers/refere=
nces to them and the like. Once that work is done, exactly how you specify =
that a subobject takes up no space does not really matter.</p>
<h2 id=3D"stateless-by-type-declaration">Stateless by type declaration</h2>
<p>An older version of this idea permitted statelessness in a form similar =
to what is specified here. But that design evolved from the needs of inner =
classes and mixins, where it was solely on an implementation of a type to b=
e used for a specific purpose.</p>
<p>As such, in that design, a class was declared stateless. Once this was d=
one, that type could only be used to declare objects as direct subobject of=
 another type, and they would be implicitly stateless. Since both inner cla=
sses and mixins are intended for only those uses, that was not a significan=
t limitation.</p>
<p>The problem with this solution is that it does not solve the general sta=
teless problem outlined in the <a href=3D"#motivation">motivation</a> secti=
on.</p>
<h1 id=3D"changelist">Changelist</h1>
<h2 id=3D"from-pre-release-v3">From pre-release v3:</h2>
<ul>
<li>Applying one possible solution for the unique identity problem.</li>
<li>Adjusting design to accept the fact that <code>is_empty</code> is not e=
nough to ensure viability for statelessness. We really need <code>is_empty<=
/code> and <code>is_standard_layout</code>, thus provoking the need for PST=
..</li>
<li>Because stateless types mean something much stronger, it is now express=
ly forbidden to have subobjects of stateless types that are not stateless t=
ypes.</li>
</ul>
<h2 id=3D"from-pre-release-v2">From pre-release v2:</h2>
<ul>
<li>Added details about the empty object identity problem, as well as a num=
ber of potential solutions.</li>
</ul>
<h2 id=3D"from-pre-release-v1">From pre-release v1:</h2>
<ul>
<li><p>Clarified that stateless types act like regular empty types in all c=
ases except when declared as direct subobjects of classes.</p></li>
<li><p>Explicitly noted that the alignment of stateless subobjects will be =
respected by their containers.</p></li>
</ul>
<h1 id=3D"standard-notes">Standard notes:</h1>
<ul>
<li>[intro.object]/5-6: Explains how base classes can be zero sized. Also e=
xplains that different instances of the same type must have distinct addres=
ses.</li>
<li>[basic.lval]/10: The &quot;strict aliasing rule&quot;.</li>
<li>[class]/4: States that member subobjects cannot be zero sized. But expl=
icitly does not mention base classes.</li>
</ul>
<h1 id=3D"acknowledgments">Acknowledgments</h1>
<p>From the C++ Future Discussions forum:</p>
<ul>
<li>Avi Kivity</li>
<li>A. Jo=C3=ABl Lamotte, who's original thread on <a href=3D"https://group=
s.google.com/a/isocpp.org/d/msg/std-proposals/u35GIuJECcQ/Yorc58iiBwAJ">Inl=
ine Classes</a> was the seed for this idea.</li>
<li>Vicente J. Botet Escriba</li>
<li>Matt Calabrese</li>
<li>Andrew Tomazos</li>
<li>Matthew Woehlke</li>
<li>Bengt Gustafsson</li>
<li>Thiago Macieira, who initially identified the unique identity problem.<=
/li>
</ul>
<div class=3D"footnotes">
<hr />
<ol>
<li id=3D"fn1"><p>It may be reasonable to use the logical <code>or</code> b=
etween the two, instead of failing on a mis-match.<a href=3D"#fnref1">=E2=
=86=A9</a></p></li>
</ol>
</div>
</body>
</html>

------=_Part_5679_467869714.1468971343841
Content-Type: text/x-markdown; charset=UTF-8; name="Stateless Subobjects.md"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename="Stateless Subobjects.md"
X-Attachment-Id: a8200b09-6926-4235-a5fc-c0b8bf4e813a
Content-ID: <a8200b09-6926-4235-a5fc-c0b8bf4e813a>

% Stateless Subobjects and Types, pre-release v4
%
% July 19, 2016

This proposal specifies the ability to declare member and base class subobj=
ects which do not take up space in the objects they are contained within. I=
t also allows the user to define classes which will always be used in such =
a fashion.

# Motivation and Scope {#motivation}

An object is stateless, conceptually speaking, if it has no non-static data=
 members. As such, the state of any particular instance is no different fro=
m another. Because of this, there is no conceptual reason why a stateless o=
bject needs to have a region of storage associated with it.

In C++, a class would be stateless if it has no non-static data members (NS=
DMs) and all of its base classes likewise are stateless as well. `is_empty_=
v` qualifies as a useful test, but technically other classes could qualify =
as well (those with virtual members/base classes).

There are many times when a user wants to use a class that the user provide=
s, but the class may or may not be logically stateless. If it is stateless,=
 then it would be best if the class which uses it would not grow in size si=
mply due to the presence of the stateless subobject. After all, a conceptua=
lly stateless object does not need to take up space to do its job.

To avoid this, users will frequently use standard layout rules and the empt=
y base optimization to allow them to have access to a stateless subobject:

=09template<typename Alloc>
=09struct DataBlock : public Alloc
=09{
=09};

In this case, if `Alloc` is empty, then so long as `DataBlock` follows stan=
dard layout rules, the user is guaranteed that `DataBlock` is no larger tha=
n it would have been if `Alloc` were not empty. Even if it does not follow =
standard layout, the compiler is free to optimize the empty base `Alloc` aw=
ay.

There are of course problems with such a use. If `Alloc` is not empty (and =
`DataBlock` does not require that it is), and `Alloc` declares a virtual fu=
nction, it is possible that `DataBlock<Alloc>` will accidentally override t=
hat virtual function. Or not quite override it and cause a compile error. W=
hereas if `Alloc` were a non-static data member, this could easily be avoid=
ed.

Equally importantly, this use of `Alloc` is simply not how a user would nat=
urally write this class. Inheritance is supposed to model an "is a" relatio=
nship. Yet conceptually, `DataBlock` is not an `Alloc`; it *has* an `Alloc`=
.. `DataBlock` uses inheritance, not to model a relationship, but as an opti=
mization tool, to keep the class from growing unnecessarily.

The intent of this proposal is to permit, among other things, classes like =
`DataBlock` to declare `Alloc` as a non-static data member. And if `Alloc` =
is empty, then `DataBlock` can use syntax to make the `Alloc` NSDM take up =
no space in `DataBlock`'s layout.

This would also be recursive, so that if `Alloc` had no NSDMs, and `DataBlo=
ck<Alloc>` had no NSDMs besides the `Alloc` member, then `DataBlock<Alloc>`=
 would also be considered an empty type. And therefore, some other type cou=
ld use it in a stateless fashion.

# Design {#design}

We define two concepts: stateless subobjects and stateless classes. A state=
less class is really just shorthand for the former; it declares that instan=
ces of the class can only be created as stateless subobjects of some other =
type.

Note: The following syntax is entirely preliminary. This proposal is not we=
dded to the idea of introducing a new keyword or somesuch. This syntax is h=
ere simply for the sake of understanding how the functionality should gener=
ally be specified. The eventual syntax could be a contextual keyword like `=
final` and `override`, or it could be something else.

## Possibly-stateless types

A possibly-stateless type (PST) is a type which could be used in a stateles=
s way. This is defined as any class type for which both `std::is_empty` and=
 `std::is_standard_layout` apply. The definition of `is_empty` is expanded =
by the [behavior of stateless subobjects](#stateless_behavior).

The standard library will need a traits class `is_possibly_stateless` to de=
tect if a type is possibly stateless.

## Stateless subobojects

A non-static data member subobject of a type can be declared stateless with=
 the following syntax:

=09struct Data
=09{
=09=09stateless Type val;
=09};
=09
A base class subobject of a type can be declared stateless with the followi=
ng syntax:

=09struct Data : public stateless Type
=09{
=09=09...
=09};

For these declarations to be well-formed, `Type` must be a PST.

`stateless` cannot be applied to:

* Members of a `union` class
* base classes that use `virtual` inheritance
* Member subobjects that are arrayed
* Variables that are not declared as non-static data members

The stateless property can be conditional, based on a compile-time conditio=
n like `noexcept`. This is done as follows:

=09template<typename Alloc>
=09struct DataBlock
=09{
=09=09stateless(is_possibly_stateless_v<Alloc>) Alloc a;
=09};

In this case, `a` will be a stateless member only if its type is a PST. If =
the condition is false, then it is as if the stateless property were not ap=
plied to the subobject.

To facilitate common use patterns, the `stateless(auto)` syntax for subobje=
cts shall be equivalent to `stateless(std::is_possibly_stateless_v<T>)`, wh=
ere `T` is the type of the subobject being declared.

Classes which contain stateless subobjects, directly or indirectly, are sub=
ject to the [Unique Identity Rule](#unique_rule). Class declarations that v=
iolate the unique identity rule are il-formed.

## Stateless behavior {#stateless_behavior}

Stateless subobjects have no effect on the layout or size of their containi=
ng object. Similarly, the rules for standard layout types ignore the presen=
ce of any stateless subobjects (a class can be standard layout with public =
stateless members and private non-stateless members). And thus, two classes=
 can be layout compatible even if they differ by the presence of stateless =
subobjects.

Stateless subobjects otherwise have the same effects on their containing ty=
pes as regular subobjects do. For example, a stateless subobject can cause =
its container to not be trivially copyable, if it has a non-trivial copy co=
nstructor (even though the object by definition has no state to copy).

The definition of "empty class" (per `std::is_empty`) must now be expanded.=
 The rules for an empty class are:

* Non-union class.
* No virtual functions.
* No virtual base classes.
* No non-empty base classes (stateless base subobjects are, by definition, =
empty).
* No non-stateless NSDMs.

In all other ways, except where detailed below, a stateless subobject works=
 identically to a non-stateless one. Stateless subobjects are initialized a=
nd destroyed just as if they were not stateless. Stateless subobjects under=
go copy and move construction and assignment along with all other subobject=
s (though they will likely not be doing much). In particular, stateless sub=
objects are still members/base classes of the types that contain them, so a=
ggregate initialization of members (and bases) will still have to take them=
 into account:

=09struct foo {};

=09struct aggregate
=09{
=09  stateless foo f;
=09  int b;
=09};

=09//It may have no state, but `f` must still be initialized.
=09aggregate agg =3D {{}, 4};

Note that the alignment of a stateless subobject will still impact the alig=
nment of the containing class. A `stateless` member declaration can include=
 an `alignas` specifier as well.

## Stateless types

The stateless property can be applied to (non-union) types as well:

=09stateless class ClassName : BaseClasses
=09{
=09=09...
=09};

The `stateless` keyword must be consistently associated with any forward de=
clarations for stateless types.

=09class ClassName;  //Not a stateless type.

=09stateless class ClassName  //Compiler error: you told me it wasn't state=
less before.
=09{
=09};

And vice-versa.

A stateless class definition is ill-formed if the class is not a PST. Howev=
er, a stateless class definition is also il-formed if it has any subobjects=
 that are not themselves of stateless types.

The size of a stateless class is not affected by being stateless. Therefore=
, the size of a stateless class shall be no different from the size of any =
other PST class.

The statelessness of a type can be conditional, just like subobjects:

=09template<typename T>
=09stateless(is_stateless_v<T>) struct Foo : public T {};
=09
Here, `Foo` may or may not be stateless, depending on whether `T` is a stat=
eless type. If the constant expression evaluates to `false`, then the class=
 is not stateless.

To make certain conditions easier, there will be the `stateless(auto)` synt=
ax. When applied to a class declaration, `stateless(auto)` will cause the c=
lass to be stateless if all of the subobjects are of stateless types.

When a stateless class is used to create an object in a way that cannot hav=
e `stateless` applied to it, then the code behaves just as it would if the =
class did not have the `stateless` keyword. Therefore, you can heap allocat=
e arrays of stateless classes, and they will function just like any heap al=
located array of PST classes. You can declare an automatic or global variab=
le of a stateless type, and it will behave as any PST class (note: implemen=
tations are free to optimize such objects to take up no stack space if poss=
ible, but they are not required to do so).

However, when a stateless class is used to declare a direct subobject of an=
other type, that subobject will be implicitly stateless. It is perfectly va=
lid to explicitly specify `stateless` on a member/base class of a stateless=
 type as well. If the conditions on the two `stateless` properties do not a=
gree (one resolves to true and the other false), then the program is il-for=
med.[^1]

Stateless subobjects created through stateless classes are exempt from the =
[unique identity rule](#unique_rule).

Declaring an array of a stateless type as an NSDM is forbidden. Stateless t=
ypes may not be used as members of a union.

The standard library will need a traits class to detect if a type is statel=
ess, since being `stateless` does have other properties.

## Stateless anonymous types

Statelessness can be applied to anonymous types as well:

=09stateless(auto) struct
=09{
=09=09Data d;
=09} varName;

The `stateless` property applies to the struct declaration, not the variabl=
e. As such, `decltype(varName)` will be a stateless type if `Data` is a sta=
teless type. Such declarations can only be made as non-static data members.

## Unique identity rule {#unique_rule}

Any class which contains a subobject which is stateless (directly or indire=
ctly) is subject to the unique identity rule. The goal of this rule is to e=
nsure that each object within a struct has [unique identity](#identity) whi=
le fulfilling the layout needs of being `stateless`. This rule is as follow=
s.

For every subobject, recursively, of a class `T`, if that subobject is decl=
ared `stateless`, and that subobject is not of a `stateless` type, then loo=
k through `T`'s subobjects, recursively. If there is another subobject of t=
hat type, and that subobject is created from a different subobject *declara=
tion*, then `T` violates the unique identity rule.

Note that "different subobject declaration" means the following:

    struct empty {};
=09struct holder { stateless empty e; };
=09
=09struct data
=09{
=09=09holder h1;
=09=09holder h2;
=09};
=09
`h2.e` does not cause a violation of the unique identity rule. The reason b=
eing that `h1.e` and `h2.e` both come from the same declaration: the defini=
tion of `holder`.

By contrast, these would be illegal:

=09struct data2
=09{
=09=09holder h1;
=09=09empty e2; //Same type as `h1::e`, but different declaration.
=09};
=09
=09struct data2a
=09{
=09=09holder h1;
=09=09stateless holder h2; //Same type as `h1`, but different declaration.
=09};
=09
Do note that the identity rule works even for derived classes and arrays of=
 types that contain stateless subobjects:

=09struct data3 : public holder
=09{
=09=09holder h2;
=09=09holder hs[40];
=09};
=09
This works because of standard layout rules. Or rather, because `data3` is =
*not* standard layout. Because of that, `data3::holder` and `data::h2` must=
 have distinct addresses. And therefore, their stateless subobjects will as=
 well.

This does forbid many cases that theoretically could work. It may be possib=
le to come up with more complex forms of this rule that allow stateless sub=
objects to be used in more places. But with added complexity comes the chan=
ce to get something wrong.

# Design rationale

A number of restrictions on the use of stateless types come from implementa=
tion restrictions or the needs of basic C++ assumptions about types. This s=
ection goes into detail about some of the rationales for the design decisio=
ns, as well as alternatives that were discarded.

## Memory locations

In C++ as it currently stands, every object needs to have a memory location=
.. And in most cases two separate objects of unrelated types cannot have the=
 *same* memory location.

Stateless subobojects effectively have to be able to break this rule. The m=
emory location of a stateless subobject is more or less irrelevant. Since t=
he type is stateless, there is no independent state to access. So one insta=
nce is functionally no different from another (pursuant to the [unique iden=
tity rule](#identity)).

As such, the general idea is that a stateless subobject could have any addr=
ess within the storage of the object which contains it. This means that a s=
tateless subobject can have the same address as any other subobject in its =
containing object's type. The standard has rules for zero-sized subobjects =
([intro.object]/5-6). At present, only base classes can qualify ([class]/4)=
, but we can build on the existing infrastructure for stateless subobjects.

This is not really an implementation problem, since stateless subobojects b=
y their very nature have no state to access. As such, the specific address =
of their `this` pointer is irrelevant. What we need, standard-wise, is to m=
odify the rules for accessing objects and aliasing to allow a stateless sub=
object to have the same address as *any* other object. Because stateless ob=
jects have no value to access, we may not even need to change [basic.lval]/=
10.

The address of a stateless subobject can be any address within the storage =
of the object that contains it. The standard need not specify exactly which=
 address.

Implementation-wise, the difficulty will be in changing how types are laid =
out. That is, modifying ABIs to allow member subobjects that have no size a=
nd enforcing EBO even when it might otherwise have been forbidden.

The behavior of the *user* converting pointers/references between two unrel=
ated stateless subobjects should still be undefined. We just need rules to =
allow stateless subobjects to be assigned a memory location at the discreti=
on of the compiler, which may not be unique from other unrelated objects.

## Stateless arrays

This design expressly forbids the declaration of stateless member subobject=
s that are arrayed. The reason for this has to do with pointer arithmetic.

In C++, the following should be perfectly valid for any type `T`, regarldes=
s of where the array of `T` is declared:

=09T t[5];
=09T *first =3D &t[0];
=09T *last =3D first + 5;
=09assert(sizeof(T) * 5 =3D=3D last - first);

The whole point of a stateless subobject is that it does not take up space =
within another type. If the array above were a member of another type, this=
 code still ought to work. But, since `sizeof(T)` is non-zero, that means t=
hat those values have to take up space somewhere. Each pointer has to be va=
lid.

Under non-array conditions, the pointer to a stateless subobject could alwa=
ys have the same address as its container (recursively, to the last non-sta=
teless container). Adding 1 to any such pointer will still be a valid addre=
ss; this is required because any object can be considered an array of 1 val=
ue ([expr.add]/4). If the containing class is an empty class with a size of=
 1, then adding one to a stateless member's pointer is no less valid than a=
dding 1 to the container's address.

When dealing with an array, this is not necessarily the case. If the statel=
ess array has a count larger than 1, and it is contained in an empty class,=
 there is no guarantee that adding a number larger than 1 will result in a =
valid address for the purposes of iteration.

Several alternatives were considered:

1. Declare that `sizeof` for stateless subobjects is zero. I am not nearly =
familiar enough with the C++ standard to know the level of horrors that thi=
s would unleash, but I can imagine that it's very bad. It would also make i=
t impossible to have a distinction between stateless subobjects and statele=
ss types, as the `sizeof` can be applied to a pointer to the object, which =
cannot know if the object it points to is stateless.

2. Declare that stateless subobjects which are arrayed will still take up s=
pace as though they were not declared `stateless`.

3. Forbid declaring arrays of stateless subobjects altogether.

Option 1 is probably out due to various potential issues. #2 seems tempting=
, but it makes the use of `stateless T arr[4];` something of a lie. Earlier=
 designs used #3, then switched to #2. But the current design goes back to =
#3 for an important reason.

In the current design, it is the *use* of a type which is stateless. Types =
can be declared stateless as well, but this really only means that all uses=
 of them to declare objects will implicitly be stateless. So this restricts=
 how the type may be used, but not the semantics of it.

Because statelessness can be applied to any PST class at its point of use, =
if a user wants to be able to use an PST class in a non-stateless way, then=
 they simply do not declare the class to be stateless.

And therefore, if you declare a class to be stateless, you truly intend for=
 it to only be used as a subobject of another type. This would be useful fo=
r a CRTP base class, for example, where it is a logical error to create an =
object of the class which is not a base class.

## Trivial copyability

Trivial copyability is another area that can be problematic with stateless =
subobjects. We explicitly forbid trivial copying into a base class subobjec=
t of another class ([basic.types]/2).

Similarly, we must explicitly forbid trivial copying into stateless suboboj=
ects. Trivial copying *from* a stateless subobject should be OK. Though thi=
s is only "OK" in the sense that the program is not ill-formed or that ther=
e us undefined behavior. The value copied is undefined, but that doesn't ma=
tter, since you could only ever use that value to initialize a type that is=
 layout compatible with an PST class. Namely, another PST class. And PST cl=
asses have no value.

## offsetof

`offsetof` will obviously not be affected by stateless subobject members of=
 another type. However, if `offsetof` is applied to a stateless subobject, =
what is the result?

I would suggest that this either be undefined or 0.

## Unique identity problem {#identity}

A non-virtual type with no data members or base class data members is empty=
 of valid data. It has no real value representation. But under current C++ =
rules, it does have one important piece of state: itself.

The present rules of C++ allow a number of cases where the addresses of two=
 object instances are equal. This usually involves subobjects: base classes=
 can have the same address as the derived class. The first member subobject=
 often has the address of the containing class. And for standard layout, em=
pty base classes will have the same address as the first member, which will=
 have the same address as the containing class.

Despite all of this, there is one inviolate rule with subobject layout: for=
 any two distinct objects of the same dynamic type `T`, they will have *dif=
ferent addresses*. Because of this rule, a type which is possibly stateless=
 can grant itself state by using its `this` pointer as a unique identifier =
to access external state.

As such, blindly applying `stateless` to any PST could have unpleasant cons=
equences. The purpose of the [unique identity rule](#unique_rule) is to avo=
id situations where two such member subobjects could have the same address.

Various alternatives were considered to solve this problem.

### Ignore the problem

One solution considered was to just ignore the problem. The scope of the pr=
oblem is such that it would only happen if:

1. The user has created a PST that gains state state through its object ide=
ntity.

2. The user (or another user) uses this type as a stateless subobject.

3. The user (or another user) uses this type as a stateless subobject more =
than once in the same object.

Users who do #1 can defend themselves against #2 simply by declaring that t=
he type has an NSDM of type `char`. Alternatively, we can define special sy=
ntax to allow users to actively prevent a PST from being used as a stateles=
s subobject.

### There is no problem

Another solution examined was to redefine the problem. It only occurs when =
two or more stateless subobjects of the same type can alias each other with=
in the same containing object. So we can simply declare that, when that hap=
pens, the objects are *not distinct objects*. One is an alias for the other=
..

As such, we have identity only of the ultimate non-stateless containing sub=
object. If the user expects (given the above example) `multiple::ns1` and `=
multiple::ns2` to be different objects, then the user is simply wrong to th=
ink so.

This sounds like ignoring the problem, but it really is different. In the p=
revious suggestion, it's a corner case. With this suggestion, we conceptual=
ly re-evaluate what it means to declare that a subobject is stateless. That=
 being stateless means that the object shares its identity shall effectivel=
y lose its identity among any other subobjects of its own type within the s=
ame non-stateless containing object.

That is, rather than declaring it to be an unfortunate bug, we embrace it a=
s a feature. As such, we *actively forbid* implementations from allowing di=
fferent stateless instances at the same level from having different address=
es. `multiple::ns1` *must* have the same address as `multiple::ns2`.

This also means that there is only one such object. This creates an interes=
ting problem with object lifetime and construction/destruction calls. Indee=
d, any per-member compiler-generation function call.

On the one hand, if there is only one such object, then there should only b=
e one constructor and one destructor call. But there are two member variabl=
es, and having only one call would be weird. Indeed, the two objects could =
be subobjects of different stateless subobjects.

What's worse is that, if the user declares a copy constructor or assignment=
 operator, they will have to list both objects in their member initializer.=
 If they declare an assignment operator, they have to list both objects.

So the only logical alternative here is that you *have* to call the constru=
ctor multiple times. In which case, the object model has to change.

In order for stateless subobjects of any kind to work, we declare that many=
 objects of different types live in the same region of storage. In order fo=
r two stateless subobjects of the same type to live in the same region of s=
torage, we have to declare that, since they have no value representation, t=
hen a memory location can conceptually hold any number of stateless subobje=
cts of any type. Even if they are the same type.

As such, constructing one member subobject begins its lifetime. Constructin=
g a second begins its lifetime. This leaves you with two objects of the sam=
e type in the same location of memory.

### Only stateless types can be stateless subobjects

With this solution, we make the assumption that, if a user declares that a =
type is `stateless`, then they are making a strong claim about this type. N=
amely that losing identity is perfectly valid, that it is reasonable for tw=
o objects of the same type to have the same address and live in the same me=
mory.

So we solve the problem by only permitting stateless subobjects of types th=
at are themselves declared stateless. That way, we know that the user expec=
ts such types to alias. This also means that stateless types can only have =
subobjects of other stateless types (lest they be able to lose identity as =
well).

This solves the unique identity problem by forcing the user to explicitly s=
pecify when it is OK to lose unique identity. However, it fails to solve th=
e general problem of people using EBO as a means for having a stateless sub=
object. They will continue to do so, as the set of `stateless` declared obj=
ects will always be smaller than the set of PST types that qualify for EBO.

### Explicitly forbid the problem cases

The unique identity problem arises because two stateless subobjects of the =
same type exist within the same containing type. So we can simply forbid th=
at. This is a special case rule, very similar to the one that prevents type=
s from being standard layout if their first NSDM is the same type as one of=
 their empty base classes.

We declare that an object which has a stateless subobject that can alias wi=
th another instance of that type is il-formed. This would be recursive, up =
the subobject containment hierarchy. That's the general idea, but the curre=
nt rule takes note of the fact that a stateless object cannot alias with ot=
her objects of its type if it is contained in the exact same object declara=
tion.

### Only stateless types can lose identity

This is effectively a combination of the prior two ideas ideas. The design =
in this paper uses this solution, as defined by the [unique identity rule](=
#unique_rule).

For all PST-but-not-stateless types, we apply a rule that forbids possible =
unique identity violations. However, if the type is declared `stateless`, t=
hen we know that the writer of the type has deliberately chosen to accept t=
hat the type lacks identity, so we permit them to be used without restricti=
on.

The current unique identity rule is quite conservative, leaving out situati=
ons where stateless subobjects cannot alias:

=09struct empty {};
=09struct alpha {stateless empty e;};
=09struct beta {stateless empty e;};

=09struct first
=09{
=09=09alpha a;
=09=09alpha b;=09//Legal
=09=09beta c;=09=09//Not legal.
=09};



# Potential issues

## The Unknown

One of the most difficult aspects of dealing with any form of stateless typ=
e system is that it represents something that is very new and very complica=
ted for C++ to deal with. As such, the wording for this needs to be quite p=
recise and comprehensive, lest we introduce subtle bugs into the standard.

A good spec doctor needs to be involved with the standardization of this fe=
ature.

# Alternative Designs Explored

There has been many alternatives towards achieving the same ends. Every suc=
h alternative has to deal with 2 fundamental rules of the C++ object model:

1. Objects are defined by a region of storage.
2. Two different object instances have different regions of storage.

This current proposal is designed to avoid changes to rule #1. Stateless su=
bobjects in this proposal still have a non-zero size. Instead, changes to r=
ule #2 are made to permit such subobjects to be able to not disturb the lay=
out of their container.

Other alternatives take a different approach to dealing with these rules.

## Magic standard library wrapper type

[This idea](https://groups.google.com/a/isocpp.org/d/msg/std-proposals/sAdq=
ngl8pew/xCjHCLpuAAAJ) is focused on just the specific case of having empty =
classes potentially take up no space in their containing classes.

It would essentially declare a standard library type that is, in the contex=
t of this proposal, something like this:

=09template<typename T>
=09stateless(auto) struct allow_zero_size : public T {...};

It is a wrapper which, when used as an NSDM, will not take up any space in =
its containing object if the given type is empty. And if it is not, then it=
 will.

The theoretical idea behind this is that it doesn't require new syntax. And=
 in that proposal, `allow_zero_size` would not be forbidden from being in a=
rrays or any of the other forbearances that this proposal forbids stateless=
 types from.

This makes the behavior of such a type rather more difficult to specify. Th=
e standard would still need to have changes to allow subobojects which take=
 up no space to work, since users have to be able to get pointers/reference=
s to them and the like. Once that work is done, exactly how you specify tha=
t a subobject takes up no space does not really matter.

## Stateless by type declaration

An older version of this idea permitted statelessness in a form similar to =
what is specified here. But that design evolved from the needs of inner cla=
sses and mixins, where it was solely on an implementation of a type to be u=
sed for a specific purpose.

As such, in that design, a class was declared stateless. Once this was done=
, that type could only be used to declare objects as direct subobject of an=
other type, and they would be implicitly stateless. Since both inner classe=
s and mixins are intended for only those uses, that was not a significant l=
imitation.

The problem with this solution is that it does not solve the general statel=
ess problem outlined in the [motivation](#motivation) section.

# Changelist

## From pre-release v3:

* Applying one possible solution for the unique identity problem.
* Adjusting design to accept the fact that `is_empty` is not enough to ensu=
re viability for statelessness. We really need `is_empty` and `is_standard_=
layout`, thus provoking the need for PST.
* Because stateless types mean something much stronger, it is now expressly=
 forbidden to have subobjects of stateless types that are not stateless typ=
es.

## From pre-release v2:

* Added details about the empty object identity problem, as well as a numbe=
r of potential solutions.

## From pre-release v1:

* Clarified that stateless types act like regular empty types in all cases =
except when declared as direct subobjects of classes.

* Explicitly noted that the alignment of stateless subobjects will be respe=
cted by their containers.

# Standard notes:

* [intro.object]/5-6: Explains how base classes can be zero sized. Also exp=
lains that different instances of the same type must have distinct addresse=
s.
* [basic.lval]/10: The "strict aliasing rule".
* [class]/4: States that member subobjects cannot be zero sized. But explic=
itly does not mention base classes.

# Acknowledgments

From the C++ Future Discussions forum:

* Avi Kivity
* A. Jo=C3=ABl Lamotte, who's original thread on [Inline Classes](https://g=
roups.google.com/a/isocpp.org/d/msg/std-proposals/u35GIuJECcQ/Yorc58iiBwAJ)=
 was the seed for this idea.
* Vicente J. Botet Escriba
* Matt Calabrese
* Andrew Tomazos
* Matthew Woehlke
* Bengt Gustafsson
* Thiago Macieira, who initially identified the unique identity problem.

[^1]: It may be reasonable to use the logical `or` between the two, instead=
 of failing on a mis-match.

[^2]: In theory, at any rate. [There is a discussion](#identity) of a case =
where empty types can effectively have state.
------=_Part_5679_467869714.1468971343841--

.


Author: "Arthur O'Dwyer" <arthur.j.odwyer@gmail.com>
Date: Tue, 19 Jul 2016 17:47:18 -0700
Raw View
--001a1146f5f225f0690538068b3c
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

On Tue, Jul 19, 2016 at 12:44 PM, Nicol Bolas <jmckesson@gmail.com> wrote:

> On Sunday, July 17, 2016 at 6:59:43 AM UTC-4, Bengt Gustafsson wrote:
>>
>>
>> Couldn't it just be demanded from the compiler to guarantee that no two
>> objects of the same type have the same address? Here is an example:
>>
>
> No. That would mean that `stateless` becomes a *suggestion*, not a
> requirement. That's bad. We're trying to *improve* EBO, not take its bad
> ideas.
>
> But in any case, if someone uses `stateless`, they should mean it. And if
> it can't be stateless, then it should be a hard error. After all, this is
> all about being able to control the layout of a type. If your layout
> controls are *optional*, why bother?
>

*All* "layout controls" in C++ are optional right now, because the
implementation is permitted to insert padding bytes anywhere it pleases
(even in a standard-layout POD struct).  Yes, yes, the members have to be
in a certain order and the first member must be at offset 0; but if the
compiler chooses to put your three consecutive S-sized objects at offsets
S+1, 2S+2, and 3S+47, there's really nothing you can do about it except
complain about its quality of implementation.  I suppose this property
would continue to hold even when S=3D=3D0.

So I think Bengt's idea deserves more than just a quick writeoff; I think
it's potentially useful.


> It would also prevent implementations from having null conversions to a
particular stateless
> subobject (that is, keeping the pointer the same as the container). And
keeping that door
> open is important for other features I want to see.

Given
    struct S { stateless M m1; stateless M m2; int x; stateless M m3; };
do you mean that you want
    assert( (void*) &s =3D=3D (void*) &s.m1 );   // I approve of this
or
    assert( (void*) &s =3D=3D (void*) &s.m2 );   // I think this is sketchy
only because m1 and m2 have the same type
    // Bengt's suggestion is to force the implementation to insert a
padding byte between m1 and m2
    // so as to preserve this assertion's falseness
or
    assert( (void*) &s =3D=3D (void*) &s.m3 );   // I think this is flat-ou=
t
crazy, fwiw
?

Also, either the mention of "other features I want to see" is a
distraction, or else it's relevant; if it's relevant, could you explain
and/or link to an explanation of those features?

=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/CADvuK0L_BFRWV%2B_k-zuwpa9-Pi2sjUwbjzFKg76qBXuX3=
fq3tQ%40mail.gmail.com.

--001a1146f5f225f0690538068b3c
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Tue, Jul 19, 2016 at 12:44 PM, Nicol Bolas <span dir=3D=
"ltr">&lt;<a href=3D"mailto:jmckesson@gmail.com" target=3D"_blank">jmckesso=
n@gmail.com</a>&gt;</span> wrote:<br><div class=3D"gmail_extra"><div class=
=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px =
0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-l=
eft-style:solid;padding-left:1ex"><div dir=3D"ltr">On Sunday, July 17, 2016=
 at 6:59:43 AM UTC-4, Bengt Gustafsson wrote:<blockquote class=3D"gmail_quo=
te" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-col=
or:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir=3D"l=
tr"><br></div></blockquote><blockquote class=3D"gmail_quote" style=3D"margi=
n:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204=
);border-left-style:solid;padding-left:1ex"><div dir=3D"ltr"><div>Couldn&#3=
9;t it just be demanded from the compiler to guarantee that no two objects =
of the same type have the same address? Here is an example:</div></div></bl=
ockquote><div><br>No. That would mean that `stateless` becomes a <i>suggest=
ion</i>, not a requirement. That&#39;s bad. We&#39;re trying to <i>improve<=
/i> EBO, not take its bad ideas.<br><br>But in any case, if someone uses `s=
tateless`, they should mean it. And if it can&#39;t be stateless, then it s=
hould be a hard error. After all, this is all about being able to control t=
he layout of a type. If your layout controls are <i>optional</i>, why bothe=
r?<br></div></div></blockquote><div><br></div><div><i><b>All</b></i> &quot;=
layout controls&quot; in C++ are optional right now, because the implementa=
tion is permitted to insert padding bytes anywhere it pleases (even in a st=
andard-layout POD struct).=C2=A0 Yes, yes, the members have to be in a cert=
ain order and the first member must be at offset 0; but if the compiler cho=
oses to put your three consecutive S-sized objects at offsets S+1, 2S+2, an=
d 3S+47, there&#39;s really nothing you can do about it except complain abo=
ut its quality of implementation.=C2=A0 I suppose this property would conti=
nue to hold even when S=3D=3D0.</div><div><br></div><div>So I think Bengt&#=
39;s idea deserves more than just a quick writeoff; I think it&#39;s potent=
ially useful.</div><div><br></div><div><br></div><div>&gt; It would also pr=
event implementations from having null conversions to a particular stateles=
s</div><div>&gt; subobject (that is, keeping the pointer the same as the co=
ntainer). And keeping that door</div><div>&gt; open is important for other =
features I want to see.</div><div><br></div><div>Given</div><div>=C2=A0 =C2=
=A0 struct S { stateless M m1; stateless M m2; int x; stateless M m3; };<br=
>do you mean that you want</div><div>=C2=A0 =C2=A0 assert( (void*) &amp;s =
=3D=3D (void*) &amp;s.m1 ); =C2=A0 // I approve of this</div><div>or</div><=
div><div>=C2=A0 =C2=A0 assert( (void*) &amp;s =3D=3D (void*) &amp;s.m2 ); =
=C2=A0 // I think this is sketchy only because m1 and m2 have the same type=
</div><div>=C2=A0 =C2=A0 // Bengt&#39;s suggestion is to force the implemen=
tation to insert a padding byte between m1 and m2</div><div>=C2=A0 =C2=A0 /=
/ so as to preserve this assertion&#39;s falseness</div></div><div><div>or<=
/div><div>=C2=A0 =C2=A0 assert( (void*) &amp;s =3D=3D (void*) &amp;s.m3 ); =
=C2=A0 // I think this is flat-out crazy, fwiw</div></div><div>?</div><div>=
<br></div><div>Also, either the mention of &quot;other features I want to s=
ee&quot; is a distraction, or else it&#39;s relevant; if it&#39;s relevant,=
 could you explain and/or link to an explanation of those features?</div><d=
iv><br></div><div>=E2=80=93Arthur</div></div></div></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/CADvuK0L_BFRWV%2B_k-zuwpa9-Pi2sjUwbjz=
FKg76qBXuX3fq3tQ%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CADvuK0L_BFRWV%=
2B_k-zuwpa9-Pi2sjUwbjzFKg76qBXuX3fq3tQ%40mail.gmail.com</a>.<br />

--001a1146f5f225f0690538068b3c--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 19 Jul 2016 23:46:23 -0700 (PDT)
Raw View
------=_Part_321_1487437693.1468997184113
Content-Type: multipart/alternative;
 boundary="----=_Part_322_923103716.1468997184114"

------=_Part_322_923103716.1468997184114
Content-Type: text/plain; charset=UTF-8



On Tuesday, July 19, 2016 at 8:47:20 PM UTC-4, Arthur O'Dwyer wrote:
>
> On Tue, Jul 19, 2016 at 12:44 PM, Nicol Bolas <jmck...@gmail.com
> <javascript:>> wrote:
>
>> On Sunday, July 17, 2016 at 6:59:43 AM UTC-4, Bengt Gustafsson wrote:
>>>
>>>
>>> Couldn't it just be demanded from the compiler to guarantee that no two
>>> objects of the same type have the same address? Here is an example:
>>>
>>
>> No. That would mean that `stateless` becomes a *suggestion*, not a
>> requirement. That's bad. We're trying to *improve* EBO, not take its bad
>> ideas.
>>
>> But in any case, if someone uses `stateless`, they should mean it. And if
>> it can't be stateless, then it should be a hard error. After all, this is
>> all about being able to control the layout of a type. If your layout
>> controls are *optional*, why bother?
>>
>
> *All* "layout controls" in C++ are optional right now, because the
> implementation is permitted to insert padding bytes anywhere it pleases
> (even in a standard-layout POD struct).  Yes, yes, the members have to be
> in a certain order and the first member must be at offset 0; but if the
> compiler chooses to put your three consecutive S-sized objects at offsets
> S+1, 2S+2, and 3S+47, there's really nothing you can do about it except
> complain about its quality of implementation.  I suppose this property
> would continue to hold even when S==0.
>
> So I think Bengt's idea deserves more than just a quick writeoff; I think
> it's potentially useful.
>

You are correct; you cannot a priori know the layout of a standard layout
struct. But you *can* a priori know if two structs are layout compatible.
And that's what we're competing with here. Namely, this:

struct empty{};

struct foo
{
  int x;
};

struct bar1 : public empty
{
  int y;
};

struct bar2
{
  int z;
  stateless empty e;
};

The C++ standard *requires* that `foo` and `bar1` have the same layout.  We
are trying to define a feature that allows us to replace `bar1` with
`bar2`. If our feature is going to be able to do that, it needs to have the
same degree of certainty. Not an optimization or quality of implementation,
but a hard *requirement*.

Because if we can't require that, why should anyone prefer the uncertainty
of `bar2` over the absolute certainty of `bar1`?

> It would also prevent implementations from having null conversions to a
> particular stateless
> > subobject (that is, keeping the pointer the same as the container). And
> keeping that door
> > open is important for other features I want to see.
>
> Given
>     struct S { stateless M m1; stateless M m2; int x; stateless M m3; };
> do you mean that you want
>     assert( (void*) &s == (void*) &s.m1 );   // I approve of this
> or
>     assert( (void*) &s == (void*) &s.m2 );   // I think this is sketchy
> only because m1 and m2 have the same type
>     // Bengt's suggestion is to force the implementation to insert a
> padding byte between m1 and m2
>     // so as to preserve this assertion's falseness
> or
>     assert( (void*) &s == (void*) &s.m3 );   // I think this is flat-out
> crazy, fwiw
> ?
>

In the current version of the proposal, the meaning of that code depends on
what `M` is declared as.

If `M` is just a regular potentially-stateless type (is_empty and
is_standard_layout), then `S` is a *compile error*. The current proposal
makes it explicitly illegal to have two subobjects of the same type, at
least one of which is declared stateless, and they can possibly alias to
the same address (note: the actual unique identity rule is rather more
well-defined, though it does cull out some valid use cases in the interests
of simplicity).

Unless of course `M` is *explicitly* declared as a `stateless` type. In
which case, this code compiles, `sizeof(S) == 1`, all three variables point
to the same location. Why is that OK? Because you declared the *type* to be
`stateless`, and therefore you specifically declared that it was OK for the
object to alias with another instance of itself.

Self-aliasing is, and must be, opt-in. If the user wants it, they can have
it, but it is a property of the type and it is not available by default.
Self-aliasing isn't a fundamental problem with C++'s object model; it's
simply something that we cannot impose upon types, since C++ has never
allowed such a thing before. Thus, having a way to explicitly say "It's OK
to self-alias me" is a good thing.

The reason for making it illegal if `M` isn't stateless is what I said
before: you don't want stateless to be a *suggestion*. Either the type can
fulfill the request made of it, or the programmer needs to be informed that
it cannot.

Lastly, think very carefully about what you're saying. Let's say we do
things your way, where instead of forbidding such declarations, we allow
it. But in these cases we bloat the type silently (even though that was
*explicitly* what the user did not want to have happen).

So... is `S` empty? Well, I recently learned that `is_empty` counts types
that aren't standard layout (due to using multiple empty base classes of
the same type), so by your reckoning, I suppose that's what would happen
here. We would declare that `S` is nominally empty, but it would not be
empty in any *useful* way. For example, you could *never* get EBO with it.

Would `S` be standard layout too? I don't think it's possible to declare
that it would be standard layout. Why? Because if you did make it standard
layout and empty... you'd break the concept of standard layout.

If a type is both standard layout and empty, then that type is *truly empty*
by the nature of its layout. The size of it should be 1, and it should be
layout-compatible with every other type that is empty and standard layout.
If you use it as the base class of another standard layout type, then you
are guaranteed that it will not take part in the layout of that type
(unless you break one of the other rules of standard layout).

A class that contains 3 stateless subobjects which take up space cannot be
both empty standard layout. It cannot be layout compatible with any other
standard layout/empty class. You cannot use it as a base class without it
disrupting layout. And so forth.

Complexities like this is why it's so much better to just flat-out *forbid*
these kinds of things. My rule for edge cases like this is that if you
can't make it truly stateless, make it *illegal*. That's the reason why
stateless arrays are forbidden, after all.

Also, either the mention of "other features I want to see" is a
> distraction, or else it's relevant; if it's relevant, could you explain
> and/or link to an explanation of those features?
>

Huh. I guess I forgot to link to the old thread
<https://groups.google.com/a/isocpp.org/forum/#!searchin/std-proposals/stateless$20inner/std-proposals/HjGujSdKXX0/27WIWTc_EwAJ>
in my initial post. I thought I had.

The main thing there is that it's very important that it be *possible* to
implement stateless subobjects them such that their pointer *always* points
to their direct containing type. If you can't do that, then stateless inner
classes would have to not be stateless (or rather, they'd bloat the state
of their container, which is *exactly* what the whole idea is trying to
avoid). That is, it's important to be able to pass a pointer/reference of
an inner class to someone, and *from that pointer alone*, the system needs
to be able to reconstruct the containing instance pointer. And the only way
I can see to do that for stateless inner class members is if the address of
the member is actually the address of the containing class itself. Always.
No matter what.

Now, since we're starting to diverge in the distinction between zero-sized
subobject and stateless types, it would not be unreasonable to say that a
zero-sized subobject could get an address that's anywhere, but a stateless
subobject would get the address of its container (since they're allowed to
freely alias anyway).

--
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/fb8c3ccd-b5e2-4b62-8024-ce93f3aab675%40isocpp.org.

------=_Part_322_923103716.1468997184114
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><br>On Tuesday, July 19, 2016 at 8:47:20 PM UTC-4, Art=
hur O&#39;Dwyer wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;=
margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=
=3D"ltr">On Tue, Jul 19, 2016 at 12:44 PM, Nicol Bolas <span dir=3D"ltr">&l=
t;<a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-mailto=3D"Ip5Jpf=
XQAgAJ" rel=3D"nofollow" onmousedown=3D"this.href=3D&#39;javascript:&#39;;r=
eturn true;" onclick=3D"this.href=3D&#39;javascript:&#39;;return true;">jmc=
k...@gmail.com</a>&gt;</span> wrote:<br><div><div class=3D"gmail_quote"><bl=
ockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-lef=
t-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padd=
ing-left:1ex"><div dir=3D"ltr">On Sunday, July 17, 2016 at 6:59:43 AM UTC-4=
, Bengt Gustafsson wrote:<blockquote class=3D"gmail_quote" style=3D"margin:=
0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);=
border-left-style:solid;padding-left:1ex"><div dir=3D"ltr"><br></div></bloc=
kquote><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;=
border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:=
solid;padding-left:1ex"><div dir=3D"ltr"><div>Couldn&#39;t it just be deman=
ded from the compiler to guarantee that no two objects of the same type hav=
e the same address? Here is an example:</div></div></blockquote><div><br>No=
.. That would mean that `stateless` becomes a <i>suggestion</i>, not a requi=
rement. That&#39;s bad. We&#39;re trying to <i>improve</i> EBO, not take it=
s bad ideas.<br><br>But in any case, if someone uses `stateless`, they shou=
ld mean it. And if it can&#39;t be stateless, then it should be a hard erro=
r. After all, this is all about being able to control the layout of a type.=
 If your layout controls are <i>optional</i>, why bother?<br></div></div></=
blockquote><div><br></div><div><i><b>All</b></i> &quot;layout controls&quot=
; in C++ are optional right now, because the implementation is permitted to=
 insert padding bytes anywhere it pleases (even in a standard-layout POD st=
ruct).=C2=A0 Yes, yes, the members have to be in a certain order and the fi=
rst member must be at offset 0; but if the compiler chooses to put your thr=
ee consecutive S-sized objects at offsets S+1, 2S+2, and 3S+47, there&#39;s=
 really nothing you can do about it except complain about its quality of im=
plementation.=C2=A0 I suppose this property would continue to hold even whe=
n S=3D=3D0.</div><div><br></div><div>So I think Bengt&#39;s idea deserves m=
ore than just a quick writeoff; I think it&#39;s potentially useful.</div><=
/div></div></div></blockquote><div><br>You are correct; you cannot a priori=
 know the layout of a standard layout struct. But you <i>can</i> a priori k=
now if two structs are layout compatible. And that&#39;s what we&#39;re com=
peting with here. Namely, this:<br><br><div class=3D"prettyprint" style=3D"=
background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); bor=
der-style: solid; border-width: 1px; word-wrap: break-word;"><code class=3D=
"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #008;" cl=
ass=3D"styled-by-prettify">struct</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> empty</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">{};</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"><br><br></span><span style=3D"color: #008;" class=3D"styled-by=
-prettify">struct</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> foo<br></span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=
=C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by-prettify">int=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> x</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">};</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"><br><br></span><span style=3D"color: #008=
;" class=3D"styled-by-prettify">struct</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"> bar1 </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">public</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> empty<br></span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=
=A0 </span><span style=3D"color: #008;" class=3D"styled-by-prettify">int</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> y</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">};</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"><br><br></span><span style=3D"color: #008;=
" class=3D"styled-by-prettify">struct</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> bar2<br></span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"><br>=C2=A0 </span><span style=3D"color: #008;" class=3D"st=
yled-by-prettify">int</span><span style=3D"color: #000;" class=3D"styled-by=
-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"><br>=
=C2=A0 stateless empty e</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"><br></span><span style=3D"color: #660;" class=3D"styled-by-prettify">}=
;</span></div></code></div><br>The C++ standard <i>requires</i> that `foo` =
and `bar1` have the same layout.=C2=A0 We are trying to define a feature th=
at allows us to replace `bar1` with `bar2`. If our feature is going to be a=
ble to do that, it needs to have the same degree of certainty. Not an optim=
ization or quality of implementation, but a hard <i>requirement</i>.<br><br=
>Because if we can&#39;t require that, why should anyone prefer the uncerta=
inty of `bar2` over the absolute certainty of `bar1`?<br><br></div><blockqu=
ote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left=
: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><div class=3D"gm=
ail_quote"><div></div><div>&gt; It would also prevent implementations from =
having null conversions to a particular stateless</div><div>&gt; subobject =
(that is, keeping the pointer the same as the container). And keeping that =
door</div><div>&gt; open is important for other features I want to see.</di=
v><div><br></div><div>Given</div><div>=C2=A0 =C2=A0 struct S { stateless M =
m1; stateless M m2; int x; stateless M m3; };<br>do you mean that you want<=
/div><div>=C2=A0 =C2=A0 assert( (void*) &amp;s =3D=3D (void*) &amp;s.m1 ); =
=C2=A0 // I approve of this</div><div>or</div><div><div>=C2=A0 =C2=A0 asser=
t( (void*) &amp;s =3D=3D (void*) &amp;s.m2 ); =C2=A0 // I think this is ske=
tchy only because m1 and m2 have the same type</div><div>=C2=A0 =C2=A0 // B=
engt&#39;s suggestion is to force the implementation to insert a padding by=
te between m1 and m2</div><div>=C2=A0 =C2=A0 // so as to preserve this asse=
rtion&#39;s falseness</div></div><div><div>or</div><div>=C2=A0 =C2=A0 asser=
t( (void*) &amp;s =3D=3D (void*) &amp;s.m3 ); =C2=A0 // I think this is fla=
t-out crazy, fwiw</div></div><div>?</div></div></div></div></blockquote><di=
v>=C2=A0</div><div>In the current version of the proposal, the meaning of t=
hat code depends on what `M` is declared as.<br><br>If `M` is just a regula=
r potentially-stateless type (is_empty and is_standard_layout), then `S` is=
 a <i>compile error</i>. The current proposal makes it explicitly illegal t=
o have two subobjects of the same type, at least one of which is declared s=
tateless, and they can possibly alias to the same address (note: the actual=
 unique identity rule is rather more well-defined, though it does cull out =
some valid use cases in the interests of simplicity).<br><br>Unless of cour=
se `M` is <i>explicitly</i> declared as a `stateless` type. In which case, =
this code compiles, `sizeof(S) =3D=3D 1`, all three variables point to the =
same location. Why is that OK? Because you declared the <i>type</i> to be `=
stateless`, and therefore you specifically declared that it was OK for the =
object to alias with another instance of itself.<br><br>Self-aliasing is, a=
nd must be, opt-in. If the user wants it, they can have it, but it is a pro=
perty of the type and it is not available by default. Self-aliasing isn&#39=
;t a fundamental problem with C++&#39;s object model; it&#39;s simply somet=
hing that we cannot impose upon types, since C++ has never allowed such a t=
hing before. Thus, having a way to explicitly say &quot;It&#39;s OK to self=
-alias me&quot; is a good thing.<br><br>The reason for making it illegal if=
 `M` isn&#39;t stateless is what I said before: you don&#39;t want stateles=
s to be a <i>suggestion</i>. Either the type can fulfill the request made o=
f it, or the programmer needs to be informed that it cannot.<br><br>Lastly,=
 think very carefully about what you&#39;re saying. Let&#39;s say we do thi=
ngs your way, where instead of forbidding such declarations, we allow it. B=
ut in these cases we bloat the type silently (even though that was <i>expli=
citly</i> what the user did not want to have happen).<br><br>So... is `S` e=
mpty? Well, I recently learned that `is_empty` counts types that aren&#39;t=
 standard layout (due to using multiple empty base classes of the same type=
), so by your reckoning, I suppose that&#39;s what would happen here. We wo=
uld declare that `S` is nominally empty, but it would not be empty in any <=
i>useful</i> way. For example, you could <i>never</i> get EBO with it.<br><=
br>Would `S` be standard layout too? I don&#39;t think it&#39;s possible to=
 declare that it would be standard layout. Why? Because if you did make it =
standard layout and empty... you&#39;d break the concept of standard layout=
..<br><br>If a type is both standard layout and empty, then that type is <i>=
truly empty</i> by the nature of its layout. The size of it should be 1, an=
d it should be layout-compatible with every other type that is empty and st=
andard layout. If you use it as the base class of another standard layout t=
ype, then you are guaranteed that it will not take part in the layout of th=
at type (unless you break one of the other rules of standard layout).<br><b=
r>A class that contains 3 stateless subobjects which take up space cannot b=
e both empty standard layout. It cannot be layout compatible with any other=
 standard layout/empty class. You cannot use it as a base class without it =
disrupting layout. And so forth.<br><br>Complexities like this is why it&#3=
9;s so much better to just flat-out <i>forbid</i> these kinds of things. My=
 rule for edge cases like this is that if you can&#39;t make it truly state=
less, make it <i>illegal</i>. That&#39;s the reason why stateless arrays ar=
e forbidden, after all.<br><br></div><blockquote class=3D"gmail_quote" styl=
e=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left:=
 1ex;"><div dir=3D"ltr"><div><div class=3D"gmail_quote"><div></div><div>Als=
o, either the mention of &quot;other features I want to see&quot; is a dist=
raction, or else it&#39;s relevant; if it&#39;s relevant, could you explain=
 and/or link to an explanation of those features?</div></div></div></div></=
blockquote><div><br>Huh. I guess I forgot to <a href=3D"https://groups.goog=
le.com/a/isocpp.org/forum/#!searchin/std-proposals/stateless$20inner/std-pr=
oposals/HjGujSdKXX0/27WIWTc_EwAJ">link to the old thread</a> in my initial =
post. I thought I had.<br><br>The main thing there is that it&#39;s very im=
portant that it be <i>possible</i> to implement stateless subobjects them s=
uch that their pointer <i>always</i> points to their direct containing type=
.. If you can&#39;t do that, then stateless inner classes would have to not =
be stateless (or rather, they&#39;d bloat the state of their container, whi=
ch is <i>exactly</i> what the whole idea is trying to avoid). That is, it&#=
39;s important to be able to pass a pointer/reference of an inner class to =
someone, and <i>from that pointer alone</i>, the system needs to be able to=
 reconstruct the containing instance pointer. And the only way I can see to=
 do that for stateless inner class members is if the address of the member =
is actually the address of the containing class itself. Always. No matter w=
hat.<br><br>Now, since we&#39;re starting to diverge in the distinction bet=
ween zero-sized subobject and stateless types, it would not be unreasonable=
 to say that a zero-sized subobject could get an address that&#39;s anywher=
e, but a stateless subobject would get the address of its container (since =
they&#39;re allowed to freely alias anyway).<br></div></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/fb8c3ccd-b5e2-4b62-8024-ce93f3aab675%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/fb8c3ccd-b5e2-4b62-8024-ce93f3aab675=
%40isocpp.org</a>.<br />

------=_Part_322_923103716.1468997184114--

------=_Part_321_1487437693.1468997184113--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Wed, 20 Jul 2016 15:41:45 -0700 (PDT)
Raw View
------=_Part_4263_73365588.1469054505896
Content-Type: multipart/alternative;
 boundary="----=_Part_4264_235529014.1469054505903"

------=_Part_4264_235529014.1469054505903
Content-Type: text/plain; charset=UTF-8

When I was documenting this idea (that is, `zero_sized` not being a binding
request) in the proposal as an alternative to fixing the unique identity
problem, I came to realize something. Well, besides the fact that I hate
this idea with the fiery intensity of a million suns.

It could be a *palatable* solution with two changes:

1: `stateless` types are immune. My most recent version of the proposal
says that if you declare a type `stateless`, then you are declaring that
the type doesn't want or expect unique identity. That should remain true:
if you use a stateless type as a subobject, it *never* disturbs the type's
layout. Even if you put 20 of them in the same type and nothing else, they
will all alias the same memory address happily.

2: `zero_sized` needs to work like empty/standard layout types in standard
layout base classes. That is, so long as you follow the standard layout
rules, they are guaranteed to be zero sized. Breaking the rules is OK;
you'll still have a functioning data structure. But the layout of the type
may be perturbed by the presence of those fields.

The latter is very important, because it allows the user to not have to
rely on "quality of implementation", so long as they're following the
rules. And thus, they have as much certainty in `zero_sized` declarations
not causing bloat as they do in empty base classes in standard layout types.

The only reason I am even *considering* this is because I haven't managed
to come up with a reasonable "unique identity rule" that only causes a
compile error in cases where aliasing is guaranteed to happen. By doing
things this way, the "unique identity rule" would simply specify the
circumstances when the user can guarantee that the layout will not be
disturbed. Effectively, it would be an addition to the standard layout
rule, since a type that violates it can't be standard layout.

Also, the user can use `static_assert(is_standard_layout_v<T>);` to detect
if the type is standard layout.

It would also mean that, since applying `zero_sized` would always be a
suggestion, if the type isn't actually empty&standard layout, there would
be no need for a compile error. And thus, no need for `zero_sized(auto)` to
suppress such compile errors.

--
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/196e0a73-40c1-48c1-b7d9-49141946291f%40isocpp.org.

------=_Part_4264_235529014.1469054505903
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">When I was documenting this idea (that is, `zero_sized` no=
t being a binding request) in the proposal as an alternative to fixing the =
unique identity problem, I came to realize something. Well, besides the fac=
t that I hate this idea with the fiery intensity of a million suns.<br><br>=
It could be a <i>palatable</i> solution with two changes:<br><br>1: `statel=
ess` types are immune. My most recent version of the proposal says that if =
you declare a type `stateless`, then you are declaring that the type doesn&=
#39;t want or expect unique identity. That should remain true: if you use a=
 stateless type as a subobject, it <i>never</i> disturbs the type&#39;s lay=
out. Even if you put 20 of them in the same type and nothing else, they wil=
l all alias the same memory address happily.<br><br>2: `zero_sized` needs t=
o work like empty/standard layout types in standard layout base classes. Th=
at is, so long as you follow the standard layout rules, they are guaranteed=
 to be zero sized. Breaking the rules is OK; you&#39;ll still have a functi=
oning data structure. But the layout of the type may be perturbed by the pr=
esence of those fields.<br><br>The latter is very important, because it all=
ows the user to not have to rely on &quot;quality of implementation&quot;, =
so long as they&#39;re following the rules. And thus, they have as much cer=
tainty in `zero_sized` declarations not causing bloat as they do in empty b=
ase classes in standard layout types.<br><br>The only reason I am even <i>c=
onsidering</i> this is because I haven&#39;t managed to come up with a reas=
onable &quot;unique identity rule&quot; that only causes a compile error in=
 cases where aliasing is guaranteed to happen. By doing things this way, th=
e &quot;unique identity rule&quot; would simply specify the circumstances w=
hen the user can guarantee that the layout will not be disturbed. Effective=
ly, it would be an addition to the standard layout rule, since a type that =
violates it can&#39;t be standard layout.<br><br>Also, the user can use `st=
atic_assert(is_standard_layout_v&lt;T&gt;);` to detect if the type is stand=
ard layout.<br><br>It would also mean that, since applying `zero_sized` wou=
ld always be a suggestion, if the type isn&#39;t actually empty&amp;standar=
d layout, there would be no need for a compile error. And thus, no need for=
 `zero_sized(auto)` to suppress such compile errors.<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/196e0a73-40c1-48c1-b7d9-49141946291f%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/196e0a73-40c1-48c1-b7d9-49141946291f=
%40isocpp.org</a>.<br />

------=_Part_4264_235529014.1469054505903--

------=_Part_4263_73365588.1469054505896--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Mon, 25 Jul 2016 20:08:25 -0700 (PDT)
Raw View
------=_Part_3607_1704225841.1469502506237
Content-Type: multipart/alternative;
 boundary="----=_Part_3608_1678601833.1469502506243"

------=_Part_3608_1678601833.1469502506243
Content-Type: text/plain; charset=UTF-8

The next revision is here.

This one makes the division between "stateless types" and "zero sized
subobjects" formal. `zero_sized` is what you apply to subobject
declarations, and `stateless` is what you apply to types.

I'm kinda at a fork in the road with the unique identity problem. The
proposal presents the same solution as before: if a type violates the
"unique identity rule", you get a hard compile error.

The problem is the sheer complexity of coming up with a simple yet
comprehensive version of the "unique identity rule". Any rule that is
sufficiently "simple" leaves out a lot of cases where aliasing cannot
possibly occur. And any rule that is even remotely comprehensive is just
too complicated to even specify in simple prose, let alone standardese.

There is a solution of course: abandon the unique identity rule and make
`zero_sized` a suggestion rather than a requirement. The proposal actually
spends some time looking over that alternative. And while I *hate it*, I
cannot deny... that it actually *works*.

Basically, this form of the "unique identity rule" is simplified because it
only works for standard layout types. `zero_sized` is effectively treated
like empty base classes in standard layout types. They are guaranteed to be
zero sized... unless you break the rules of standard layout by using the
same base class type twice or having the first NSDM match a base class
type. This version simply adds all other `zero_sized` declared subobject to
that list of types that cannot appear more than once. If they do, then the
type is no longer standard layout and thus the compiler is free to do
whatever it wants with the layout.

It even permits users to enforce whether layout can be maintained, since
you can always `static_assert(is_standard_layout_v<T>)` on the type. This
also means that `zero_sized(auto)` is not necessary, since any use of
`zero_sized` is just a suggestion (though this would make the wording a bit
more odd, since only an empty type can actually be zero sized, regardless
of its declaration).

Personally, I much prefer having `zero_sized` be a hard requirement. And
yet, I can't deny the simplicity (and orthogonality with empty base
classes) that having `zero_sized` only work in standard layout types.

Which is your preference? The proposal attached here presents both, though
the `zero_sized`-as-suggestion part is down in the "Unique Identity
Problem" section.

But in either case, `stateless` declared types are always exempt from this
sort of issue. They can alias with one another just fine (which is why we
require the type to declare itself such), so the compiler need not insert
special layout stuff to prevent that.

--
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/094db9bd-faaf-4b7a-be39-3997c2f89244%40isocpp.org.

------=_Part_3608_1678601833.1469502506243
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">The next revision is here.<br><br>This one makes the divis=
ion between &quot;stateless types&quot; and &quot;zero sized subobjects&quo=
t; formal. `zero_sized` is what you apply to subobject declarations, and `s=
tateless` is what you apply to types.<br><br>I&#39;m kinda at a fork in the=
 road with the unique identity problem. The proposal presents the same solu=
tion as before: if a type violates the &quot;unique identity rule&quot;, yo=
u get a hard compile error.<br><br>The problem is the sheer complexity of c=
oming up with a simple yet comprehensive version of the &quot;unique identi=
ty rule&quot;. Any rule that is sufficiently &quot;simple&quot; leaves out =
a lot of cases where aliasing cannot possibly occur. And any rule that is e=
ven remotely comprehensive is just too complicated to even specify in simpl=
e prose, let alone standardese.<br><br>There is a solution of course: aband=
on the unique identity rule and make `zero_sized` a suggestion rather than =
a requirement. The proposal actually spends some time looking over that alt=
ernative. And while I <b>hate it</b>, I cannot deny... that it actually <i>=
works</i>.<br><br>Basically, this form of the &quot;unique identity rule&qu=
ot; is simplified because it only works for standard layout types. `zero_si=
zed` is effectively treated like empty base classes in standard layout type=
s. They are guaranteed to be zero sized... unless you break the rules of st=
andard layout by using the same base class type twice or having the first N=
SDM match a base class type. This version simply adds all other `zero_sized=
` declared subobject to that list of types that cannot appear more than onc=
e. If they do, then the type is no longer standard layout and thus the comp=
iler is free to do whatever it wants with the layout.<br><br>It even permit=
s users to enforce whether layout can be maintained, since you can always `=
static_assert(is_standard_layout_v&lt;T&gt;)` on the type. This also means =
that `zero_sized(auto)` is not necessary, since any use of `zero_sized` is =
just a suggestion (though this would make the wording a bit more odd, since=
 only an empty type can actually be zero sized, regardless of its declarati=
on).<br><br>Personally, I much prefer having `zero_sized` be a hard require=
ment. And yet, I can&#39;t deny the simplicity (and orthogonality with empt=
y base classes) that having `zero_sized` only work in standard layout types=
..<br><br>Which is your preference? The proposal attached here presents both=
, though the `zero_sized`-as-suggestion part is down in the &quot;Unique Id=
entity Problem&quot; section.<br><br>But in either case, `stateless` declar=
ed types are always exempt from this sort of issue. They can alias with one=
 another just fine (which is why we require the type to declare itself such=
), so the compiler need not insert special layout stuff to prevent that.<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/094db9bd-faaf-4b7a-be39-3997c2f89244%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/094db9bd-faaf-4b7a-be39-3997c2f89244=
%40isocpp.org</a>.<br />

------=_Part_3608_1678601833.1469502506243--

------=_Part_3607_1704225841.1469502506237
Content-Type: text/html; charset=UTF-8; name="Stateless Subobjects.html"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename="Stateless Subobjects.html"
X-Attachment-Id: 4f0cd507-8039-4446-aa37-4fe4bcd85924
Content-ID: <4f0cd507-8039-4446-aa37-4fe4bcd85924>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.=
w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns=3D"http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8" =
/>
  <meta http-equiv=3D"Content-Style-Type" content=3D"text/css" />
  <meta name=3D"generator" content=3D"pandoc" />
  <meta name=3D"date" content=3D"2016-07-25" />
  <title>Zero sized Subobjects and Stateless Types, pre-release v5</title>
  <style type=3D"text/css">code{white-space: pre;}</style>
</head>
<body>
<div id=3D"header">
<h1 class=3D"title">Zero sized Subobjects and Stateless Types, pre-release =
v5</h1>
<h3 class=3D"date">July 25, 2016</h3>
</div>
<div id=3D"TOC">
<ul>
<li><a href=3D"#motivation">Motivation and Scope</a></li>
<li><a href=3D"#design">Design</a><ul>
<li><a href=3D"#empty-layout-type">Empty layout type</a></li>
<li><a href=3D"#zero-sized-subobojects">Zero sized subobojects</a></li>
<li><a href=3D"#zero_sized_behavior">Zero-sized behavior</a></li>
<li><a href=3D"#stateless-types">Stateless types</a></li>
<li><a href=3D"#stateless-anonymous-types">Stateless anonymous types</a></l=
i>
<li><a href=3D"#unique_rule">Unique identity rule</a></li>
</ul></li>
<li><a href=3D"#design-rationale">Design rationale</a><ul>
<li><a href=3D"#memory-locations">Memory locations</a></li>
<li><a href=3D"#arrays-of-zero-sized-objects">Arrays of zero sized objects<=
/a></li>
<li><a href=3D"#trivial-copyability">Trivial copyability</a></li>
<li><a href=3D"#offsetof">offsetof</a></li>
<li><a href=3D"#identity">Unique identity problem</a></li>
</ul></li>
<li><a href=3D"#potential-issues">Potential issues</a><ul>
<li><a href=3D"#the-unknown">The Unknown</a></li>
</ul></li>
<li><a href=3D"#alternative-designs-explored">Alternative Designs Explored<=
/a><ul>
<li><a href=3D"#magic-standard-library-wrapper-type">Magic standard library=
 wrapper type</a></li>
<li><a href=3D"#zero-sized-by-type-declaration">Zero sized by type declarat=
ion</a></li>
</ul></li>
<li><a href=3D"#changelist">Changelist</a><ul>
<li><a href=3D"#from-pre-release-v4">From pre-release v4:</a></li>
<li><a href=3D"#from-pre-release-v3">From pre-release v3:</a></li>
<li><a href=3D"#from-pre-release-v2">From pre-release v2:</a></li>
<li><a href=3D"#from-pre-release-v1">From pre-release v1:</a></li>
</ul></li>
<li><a href=3D"#standard-notes">Standard notes:</a></li>
<li><a href=3D"#acknowledgments">Acknowledgments</a></li>
</ul>
</div>
<p>This proposal specifies the ability to declare member and base class sub=
objects which do not take up space in the objects they are contained within=
.. It also allows the user to define classes which will always be used in su=
ch a fashion.</p>
<h1 id=3D"motivation">Motivation and Scope</h1>
<p>C++'s object model does not allow for the size of any complete type to b=
e 0. Every complete object must take up a certain region of storage.</p>
<p>However, the object model does permit the layout of a class to allocate =
no storage to a particular subobject. The standard even effectively mandate=
s this through standard layout rules: an empty, standard layout base class =
in a standard layout type must effectively have zero storage within the cla=
ss it is a base class of. This does not affect the <code>sizeof</code> the =
base class subobject, as stated in [expr.sizeof]/2.</p>
<p>This proposal is to expand these zero sized subobjects in two ways. Firs=
t, to enforce that a particular base class subobject will be zero sized. Se=
cond, and most importantly, to enforce that a particular <em>member</em> su=
bobject will be zero sized.</p>
<p>One of the primary use cases for this feature is as follows.</p>
<p>There are many times when a user wants to use a class that the user prov=
ides, but the class may or may not have members. If it is has no members, t=
hen the class using should not grow in size simply due to the presence of a=
n empty subobject. After all, an object which has no members does not need =
to take up space to do its job.</p>
<p>To avoid this, users will frequently use standard layout rules and the e=
mpty base optimization to allow them to have access to a zero sized subobje=
ct:</p>
<pre><code>template&lt;typename Alloc&gt;
struct DataBlock : public Alloc
{
};</code></pre>
<p>In this case, if <code>Alloc</code> is empty, then so long as <code>Data=
Block</code> follows standard layout rules, the user is guaranteed that <co=
de>DataBlock</code> is no larger than it would have been if <code>Alloc</co=
de> were not empty. Even if it does not follow standard layout, the compile=
r is free to make the empty base <code>Alloc</code> zero sized.</p>
<p>There are problems with such a use. If <code>Alloc</code> is not empty (=
and <code>DataBlock</code> does not require that it is), and <code>Alloc</c=
ode> declares a virtual function, it is possible that <code>DataBlock&lt;Al=
loc&gt;</code> will accidentally override that virtual function. Or not qui=
te override it and cause a compile error. Whereas if <code>Alloc</code> wer=
e a non-static data member, this could easily be avoided.</p>
<p>Equally importantly, this use of <code>Alloc</code> is simply not how a =
user would naturally write this class. Inheritance is supposed to model an =
&quot;is a&quot; relationship. Yet conceptually, <code>DataBlock</code> is =
not an <code>Alloc</code>; it <em>has</em> an <code>Alloc</code>. <code>Dat=
aBlock</code> uses inheritance, not to properly model the relationship, but=
 simply as an optimization tool, to keep the class from growing unnecessari=
ly.</p>
<p>Another problem arises if <code>Alloc</code> is <em>not</em> empty and i=
f <code>DataBlock</code> wanted to have members of its own. In that case, <=
code>DataBlock&lt;Alloc&gt;</code> could not be a standard layout type, sin=
ce both itself and the base class have NSDMs. If we had instead made <code>=
Alloc</code> an actual member, then whether <code>DataBlock</code> is stand=
ard layout depends on whether <code>Alloc</code> is.</p>
<p>The intent of this proposal is to permit, among other things, classes li=
ke <code>DataBlock</code> to declare <code>Alloc</code> as a non-static dat=
a member. And if <code>Alloc</code> is empty, then <code>DataBlock</code> c=
an use syntax to make the <code>Alloc</code> NSDM take up no space in <code=
>DataBlock</code>'s layout.</p>
<p>This would also be recursive, so that if <code>Alloc</code> had no NSDMs=
, and <code>DataBlock&lt;Alloc&gt;</code> had no NSDMs besides the <code>Al=
loc</code> member, then <code>DataBlock&lt;Alloc&gt;</code> would also be c=
onsidered an empty type. And therefore, some other type could use it in a z=
ero sized fashion.</p>
<p>This proposal also pushes forth the concept of a &quot;stateless type&qu=
ot;. This is a type which, when declared as a subobject, will always be use=
d in a zero sized fashion. But it means something more. It represents a typ=
e which fundamentally lacks identity. The C++ object model requires every i=
nstance of an object to have a distinct address. But most empty types don't=
 care about having a distinct address.</p>
<p>For the purposes of this proposal, stateless types are used as a way to =
get around a fundamental limitation of C++'s object model. Future proposals=
 however can build upon this to add more functionality.</p>
<h1 id=3D"design">Design</h1>
<p>Note: The following syntax is entirely preliminary. This proposal is not=
 wedded to the idea of introducing new keywords or somesuch. This syntax is=
 here simply for the sake of understanding how the functionality should gen=
erally be specified. The eventual syntax could be a contextual keyword like=
 <code>final</code> and <code>override</code>, or it could be something els=
e entirely.</p>
<h2 id=3D"empty-layout-type">Empty layout type</h2>
<p>The <code>is_empty</code> trait is true for a class which has no NSDMs i=
n itself or any of its base classes, as well as no virtual functions or inh=
eritance. It is also restricted to class types.</p>
<p>However, that alone does not mean that the type can functionally be zero=
 sized within a subobject. An empty type can have the same base class insta=
nce multiple times. The C++ object model does not allow two object instance=
s of the same type to have the same address. So the layout of this &quot;em=
pty&quot; type will have to be larger than a truly empty type. This means t=
hat the type cannot be zero sized when used as a subobject.</p>
<p>To be able to be zero sized, a type must be empty as well as standard-la=
yout, since the standard-layout rules restrict types from having the same b=
ase class instance multiple types.</p>
<p>Thus, we define the concept of an empty layout type. An empty layout typ=
e is a class for which both <code>std::is_empty</code> and <code>std::is_st=
andard_layout</code> are true.</p>
<p>The standard library will need a traits class <code>is_empty_layout</cod=
e> to detect if a type has an empty layout.</p>
<h2 id=3D"zero-sized-subobojects">Zero sized subobojects</h2>
<p>A non-static data member subobject of a type can be declared to be zero =
sized with the following syntax:</p>
<pre><code>struct Data
{
    zero_sized Type val;
};</code></pre>
<p>A base class subobject of a type can be declared to be zero sized with t=
he following syntax:</p>
<pre><code>struct Data : public zero_sized Type
{
    ...
};</code></pre>
<p>For these declarations to be well-formed, <code>Type</code> must be an e=
mpty layout type.</p>
<p><code>zero_sized</code> cannot be applied to:</p>
<ul>
<li>Members of a <code>union</code> class</li>
<li>base classes that use <code>virtual</code> inheritance</li>
<li>Member subobjects that are arrayed</li>
<li>Variables that are not declared as non-static data members</li>
</ul>
<p>The <code>zero_sized</code> property can be conditional, based on the ty=
pe being declared, using this syntax:</p>
<pre><code>template&lt;typename Alloc&gt;
struct DataBlock
{
    zero_sized(auto) Alloc a;
};</code></pre>
<p>The subobject <code>a</code> will be a zero sized member only if its typ=
e is empty layouyt.</p>
<p>Classes which contain zero_sized subobjects, directly or indirectly, are=
 subject to the <a href=3D"#unique_rule">Unique Identity Rule</a>. Class de=
clarations that violate the unique identity rule are il-formed.</p>
<h2 id=3D"zero_sized_behavior">Zero-sized behavior</h2>
<p>Zero sized subobjects have no effect on the layout or size of their cont=
aining object. Similarly, the rules for standard layout types ignore the pr=
esence of any zero sized subobjects (a class can be standard layout with pu=
blic zero sized members and private non-zero sized members). And thus, two =
classes can be layout compatible even if they differ by the presence of zer=
o sized subobjects.</p>
<p>Zero sized subobjects otherwise have the same effects on their containin=
g types as regular subobjects do. For example, a zero sized subobject can c=
ause its container to not be trivially copyable, if it has a non-trivial co=
py constructor (even though the object by definition has no state to copy).=
</p>
<p>The definition of &quot;empty class&quot; (per <code>std::is_empty</code=
>) must now be expanded. The rules for an empty class are:</p>
<ul>
<li>Non-union class</li>
<li>No virtual functions</li>
<li>No virtual base classes</li>
<li>No non-empty base classes (zero sized base subobjects are, by definitio=
n, empty)</li>
<li>No non-zero sized NSDMs</li>
</ul>
<p>In all other ways, except where detailed below, a zero sized subobject w=
orks identically to a non-zero sized one. zero sized subobjects are initial=
ized and destroyed just as if they were not zero sized. Zero sized subobjec=
ts undergo copy and move construction and assignment along with all other s=
ubobjects (though they will likely not be doing much). In particular, zero =
sized subobjects are still members/base classes of the types that contain t=
hem, so aggregate initialization of members (and bases) will still have to =
take them into account:</p>
<pre><code>struct foo {};

struct aggregate
{
  zero_sized foo f;
  int b;
};

//It may have no state, but `f` must still be initialized.
aggregate agg =3D {{}, 4};</code></pre>
<p>Note that the alignment of a zero sized subobject will still impact the =
alignment of the containing class. A <code>zero_sized</code> member declara=
tion can include an <code>alignas</code> specifier as well.</p>
<h2 id=3D"stateless-types">Stateless types</h2>
<p>A type can be declared to have the stateless property:</p>
<pre><code>stateless class ClassName : BaseClasses
{
    ...
};</code></pre>
<p>The <code>stateless</code> keyword must be consistently associated with =
any forward declarations for stateless types.</p>
<pre><code>class ClassName;  //Not a stateless type.

stateless class ClassName  //Compiler error: you told me it wasn&#39;t stat=
eless before.
{
};</code></pre>
<p>And vice-versa.</p>
<p>A stateless class definition is ill-formed if the class is not a empty l=
ayout type. However, a stateless class definition is also il-formed if it h=
as any subobjects that are not themselves of stateless types.</p>
<p>The size of a stateless class is not affected by being stateless. Theref=
ore, the size of a stateless class shall be no different from the size of a=
ny other empty layout class.</p>
<p>The statelessness of a type can be conditional:</p>
<pre><code>template&lt;typename T&gt;
stateless(auto) struct Foo : public T {};</code></pre>
<p>This will declare <code>Foo</code> to be a stateless type if all of its =
subobjects are also stateless. Note that, even if <code>stateless(auto)</co=
de> is used, the class definition must not have array member subobjects.</p=
>
<p>The fact that a class is declared stateless has no effect on most uses o=
f that type. When using the type to create an object that is not a subobjec=
t of another type, everything behaves normally.Therefore, you can heap allo=
cate arrays of stateless classes, and they will function just like any heap=
 allocated array of PST classes. You can declare an automatic or global var=
iable of a stateless type, and it will behave as any PST class (note: imple=
mentations are free to optimize such objects to take up no space if possibl=
e, but they are not required to do so).</p>
<p>However, when a stateless class is used to declare a direct subobject of=
 another type, that subobject declaration will implicitly be zero sized. It=
 is perfectly valid to explicitly specify <code>zero_sized</code> on a memb=
er/base class of a stateless type as well.</p>
<p>Zero sized subobjects created through stateless classes are exempt from =
the <a href=3D"#unique_rule">unique identity rule</a>.</p>
<p>Declaring an array of a stateless type as an NSDM is il-formed. Stateles=
s types may not be used as members of a union.<a href=3D"#fn1" class=3D"foo=
tnoteRef" id=3D"fnref1"><sup>1</sup></a></p>
<p>The standard library will need a traits class to detect if a type is sta=
teless, since this does restrict the type's use.</p>
<h2 id=3D"stateless-anonymous-types">Stateless anonymous types</h2>
<p>Statelessness can be applied to anonymous types as well:</p>
<pre><code>stateless(auto) struct
{
    Data d;
} varName;</code></pre>
<p>The <code>stateless</code> property applies to the struct declaration, n=
ot the variable. As such, <code>decltype(varName)</code> will be a stateles=
s type if <code>Data</code> is a stateless type. Such declarations can only=
 be made as non-static data members.</p>
<h2 id=3D"unique_rule">Unique identity rule</h2>
<p>Any class which contains (directly or indirectly) a subobject which is z=
ero sized is subject to the unique identity rule. The goal of this rule is =
to ensure that each object within a struct has <a href=3D"#identity">unique=
 identity</a> while fulfilling the layout requirements of zero-sized subobj=
ects. This rule is as follows.</p>
<p>For every subobject, recursively, of a class <code>T</code>, if that sub=
object is declared <code>zero_sized</code>, and that subobject is not of a =
<code>stateless</code> type, then look through <code>T</code>'s subobjects,=
 recursively. If there is another subobject of that type (whether zero size=
d or not), and that subobject is created from a different subobject <em>dec=
laration</em>, then <code>T</code> violates the unique identity rule.</p>
<p>Note that &quot;different subobject declaration&quot; means the followin=
g:</p>
<pre><code>struct empty {};
struct holder { zero_sized empty e; };

struct data
{
    holder h1;
    holder h2;
};</code></pre>
<p><code>h2.e</code> does not cause a violation of the unique identity rule=
.. The reason being that <code>h1.e</code> and <code>h2.e</code> both come f=
rom the same declaration: the definition of <code>holder</code>.</p>
<p>By contrast, these would be illegal:</p>
<pre><code>struct data2
{
    holder h1;
    empty e2; //Same type as `h1::e`, but different declaration.
};

struct data2a
{
    holder h1;
    zero_sized holder h2; //Same type as `h1`, but different declaration.
};</code></pre>
<p>Do note that the identity rule works even for derived classes and arrays=
 of types that contain zero_sized subobjects:</p>
<pre><code>struct data3 : public holder
{
    holder h2;
    holder hs[40];
};</code></pre>
<p>This works because of standard layout rules. Or rather, because <code>da=
ta3</code> is <em>not</em> standard layout. Because of that, <code>data3::h=
older</code> and <code>data::h2</code> must have distinct addresses. And th=
erefore, their zero_sized subobjects will as well.</p>
<p>This does forbid many cases that theoretically could work. It may be pos=
sible to come up with more complex forms of this rule that allow zero sized=
 subobjects to be used in more places. But with added complexity comes the =
chance to get something wrong.</p>
<h3 id=3D"once-more-with-complexity">Once more with complexity</h3>
<p>This is a more complex definition of the rule that would permit users mo=
re valid cases.</p>
<p>Let us define the concept of a &quot;potentially aliasing subobject.&quo=
t; A subobject is potentially aliasing if the address of that subobject <em=
>might</em> alias with the containing object itself. This requires casting =
a wide net, since implementations are explicitly allowed to vary. For some =
type <code>T</code>, the subobjects which are potentially aliasing are:</p>
<ul>
<li>If <code>T</code> is a union, then all of its NSDMs</li>
<li>If <code>T</code> is not a union,
<ul>
<li>All zero sized NSDMs</li>
<li>All (non-virtual?) base class subobjects</li>
<li>The first non-zero sized NSDM of each access class. If the first such m=
ember is an array, then only the first array element is considered</li>
</ul></li>
</ul>
<p>This rule applies recursively. For each subobject, its potentially alias=
ing subobjects are added to the list.</p>
<p>A type violates the unique identity rule if there is a potentially alias=
ing subobject declared <code>zero_sized</code>, who's type is <em>not</em> =
declared <code>stateless</code>, and there is another potentially aliasing =
subobject of the same type (whether declared <code>zero_sized</code> or not=
).</p>
<p>This permits the following case, which was illegal under the first defin=
ition:</p>
<pre><code>struct data2
{
    holder h1;
    empty e2;
};</code></pre>
<p>This is now legal because <code>e2</code> is not potentially aliasing an=
d therefore will not be considered. However, if it <code>empty</code> had b=
een a base class or <code>e2</code> was declared stateless, then it would v=
iolate the rule.</p>
<p>Consider these:</p>
<pre><code>struct data4a : holder
{
    holder h1;
    empty e2;
};

struct data4b : holder
{
    empty e2;
    holder h1;
};</code></pre>
<p>Neither of these are legal. The base class <code>holder</code> has a zer=
o sized <code>empty</code> NSDM. So whether <code>holder</code> or <code>em=
pty</code> is first, there is a potential alias with the base class.</p>
<p>Note that C++'s general forbearance of aliasing with the same type preve=
nts <code>data4a</code> from being a genuine case of aliasing. Even though =
<code>holder</code> is an empty class, <code>data4a</code> isn't standard l=
ayout because the base class is the same type as the first NSDM. So the sta=
ndard requires that the base class and the first member have different addr=
esses. Thus, the two zero sized members of each cannot alias. So this is a =
false positive.</p>
<h1 id=3D"design-rationale">Design rationale</h1>
<p>A number of restrictions on the use of zero sized subobjects come from i=
mplementation restrictions or the needs of basic C++ assumptions about type=
s. This section goes into detail about some of the rationales for the desig=
n decisions, as well as alternatives that were discarded.</p>
<h2 id=3D"memory-locations">Memory locations</h2>
<p>C++'s object model already permits the concept of zero sized subobjects =
([intro.object]/5-6). At present, these are only applied to base classes ([=
class]/4), and only <em>required</em> under standard layout rules ([class]/=
7). Such zero sized subobjects are permitted to have the same address as th=
eir containing object.</p>
<p>We simply want to piggy-back off of these rules. However, this my cause =
problems with strict aliasing rules, as we would have two unrelated types w=
hich have the same address (two of the same type with the same address is c=
overed under the <a href=3D"#identity">unique identity rule</a>).</p>
<p>So we might need an alteration to [basic.lval]/10 to permit zero sized s=
ubobjects to work. It would be an added exemption to the list of exemptions=
 there.</p>
<p>I do not believe that this is an implementation problem, since zero size=
d subobojects by their very nature have no state to access. As such, the sp=
ecific address of their <code>this</code> pointer is irrelevant (again, pur=
suant to unique identity).</p>
<p>Given that the address of a zero sized subobject could be any valid addr=
ess within the object, should we declare that the address is the address of=
 its containing object? This would match with the address for zero sized ba=
se class subobjects.</p>
<p>Implementation-wise, the difficulty will be in changing how types are la=
id out. That is, modifying ABIs to allow member subobjects that have no siz=
e and enforcing EBO even when it might otherwise have not been performed.</=
p>
<p>The behavior of the <em>user</em> converting pointers/references between=
 two unrelated zero sized subobjects should still be undefined.</p>
<h2 id=3D"arrays-of-zero-sized-objects">Arrays of zero sized objects</h2>
<p>This design expressly forbids the declaration of zero sized member subob=
jects that are arrayed. The reason for this has to do with pointer arithmet=
ic.</p>
<p>In C++, the following should be perfectly valid for any type <code>T</co=
de>, regarldess of where the array of <code>T</code> is declared:</p>
<pre><code>T t[5];
T *first =3D &amp;t[0];
T *last =3D first + 5;
assert(sizeof(T) * 5 =3D=3D last - first);</code></pre>
<p>The whole point of a zero sized subobject is that it does not take up sp=
ace within another type. If the array above were a member of another type, =
this code still ought to work. But, since <code>sizeof(T)</code> is non-zer=
o, that means that those values have to take up space somewhere. Each point=
er has to be valid.</p>
<p>Under non-array conditions, the pointer to a zero sized subobject could =
always have the same address as its container (recursively, to the last non=
-zero sized container). Adding 1 to any such pointer will still be a valid =
address; this is required because any object can be considered an array of =
1 value ([expr.add]/4). If the containing class is an empty class with a si=
ze of 1, then adding one to a zero sized member's pointer is no less valid =
than adding 1 to the container's address.</p>
<p>When dealing with an array, this is not necessarily the case. If the arr=
ay of zero sized objects has a count larger than 1, there is no guarantee t=
hat adding a number larger than 1 will result in a valid address for the pu=
rposes of iteration.</p>
<p>Several alternatives were considered:</p>
<ol style=3D"list-style-type: decimal">
<li><p>Declare that <code>sizeof</code> for zero sized subobjects is zero. =
I am not nearly familiar enough with the C++ standard to know the level of =
horrors that this would unleash, but I can imagine that it's very bad. It w=
ould also make it impossible to have a distinction between zero sized subob=
jects and stateless types, as the <code>sizeof</code> can be applied to a p=
ointer to the object, which cannot know if the object it points to is a zer=
o sized subobject.</p></li>
<li><p>Declare that zero sized subobjects which are arrayed will still take=
 up space as though they were not declared <code>zero sized</code>.</p></li=
>
<li><p>Forbid declaring arrays of zero sized subobjects altogether.</p></li=
>
</ol>
<p>Option 1 is probably out due to various potential issues. #2 seems tempt=
ing, but it makes the use of <code>zero_sized T arr[4];</code> something of=
 a lie. Earlier designs used #3, then switched to #2. But the current desig=
n goes back to #3 for an important reason.</p>
<p>In the current design, it is the <em>use</em> of a type which is zero si=
zed. Because this can be applied to any empty layout class at its point of =
use, if a user wants to be able to use an empty layout class in a non-zero-=
sized way within a class (such as an array), then they simply do not declar=
e the class to be <code>stateless</code>.</p>
<h2 id=3D"trivial-copyability">Trivial copyability</h2>
<p>Trivial copyability is another area that can be problematic with zero si=
ze subobjects. We explicitly forbid trivial copying into a base class subob=
ject of another class ([basic.types]/2).</p>
<p>Similarly, we must explicitly forbid trivial copying into zero sized sub=
obojects. Trivial copying <em>from</em> a zero sized subobject should be OK=
.. Though this is only &quot;OK&quot; in the sense that the program is not i=
ll-formed or that there us undefined behavior. The value copied is undefine=
d, but that doesn't matter, since you could only ever use that value to ini=
tialize a type that is layout compatible with an PST class. Namely, another=
 PST class. And PST classes have no value.</p>
<h2 id=3D"offsetof">offsetof</h2>
<p><code>offsetof</code> will obviously not be affected by zero sized subob=
ject members of another type. However, if <code>offsetof</code> is applied =
to a zero sized subobject, what is the result?</p>
<p>If we define the pointer to a zero sized subobject to be the same as its=
 container, then the <code>offsetof</code> should be 0. Otherwise, the <cod=
e>offsetof</code> should be undefined but within the region of storage for =
its container.</p>
<h2 id=3D"identity">Unique identity problem</h2>
<p>An empty type has no valid data; it has no real value representation. Bu=
t under current C++ rules, it does have one important piece of state: itsel=
f.</p>
<p>The present rules of C++ allow a number of cases where the addresses of =
two object instances are equal. This involves subobjects: base classes can =
have the same address as the derived class. The first member subobject ofte=
n has the address of the containing class. And for standard layout types, e=
mpty base classes will have the same address as the first member, which wil=
l have the same address as the containing class.</p>
<p>Despite all of this, there is one inviolate rule with subobject layout: =
for any two distinct objects of the same dynamic type <code>T</code>, they =
will have <em>different addresses</em>. Because of this rule, an empty type=
 can grant itself state by using its <code>this</code> pointer as a unique =
identifier, with the state being stored and accessed externally to the obje=
ct instance.</p>
<p>However, in order to make a subobject zero sized, in order for it to not=
 affect the layout of its containing type, we have to accept that the point=
er value could alias with another object. And therefore, the address of one=
 instance of a type could alias with the address of another instance. If th=
e type were written to use external state based on its <code>this</code> po=
inter (or if code using that type were written expecting it), then we would=
 break that expectation and therefore potentially that code.</p>
<p>As such, blindly applying <code>zero_sized</code> to any empty layout ty=
pe could have unpleasant consequences. Various alternatives were considered=
 to solve this problem; the solution proposed here is the last one presente=
d, and is implemented in the <a href=3D"#design">design section above</a>.<=
/p>
<h3 id=3D"ignore-the-problem">Ignore the problem</h3>
<p>One solution considered was to just ignore the problem. The scope of the=
 problem is such that it would only happen if:</p>
<ol style=3D"list-style-type: decimal">
<li><p>The user has created an empty layout type that gains state state thr=
ough its object identity.</p></li>
<li><p>The type is used as a zero sized subobject.</p></li>
<li><p>The type is used as a zero sized subobject which aliases with anothe=
r instance of itself within the same object.</p></li>
</ol>
<p>Users who do #1 can defend themselves against #2 simply by declaring tha=
t the type has an NSDM of type <code>char</code>. Alternatively, we can def=
ine special syntax to allow users to actively prevent a PST from being used=
 as a stateless subobject.</p>
<h3 id=3D"there-is-no-problem">There is no problem</h3>
<p>Another solution examined was to redefine the problem. It only occurs wh=
en two or more zero sized subobjects of the same type can alias each other =
within the same containing object. So we can simply declare that, when that=
 happens, the objects are <em>not distinct objects</em>. One is an alias fo=
r the other.</p>
<p>As such, we have identity only of the ultimate non-zero sized containing=
 subobject. If the user expects (given the above example) <code>multiple::n=
s1</code> and <code>multiple::ns2</code> to be different objects, then the =
user is simply wrong to think so.</p>
<p>This sounds like ignoring the problem, but it really is different. In th=
e previous suggestion, it's a corner case. With this suggestion, we concept=
ually re-evaluate what it means to declare that a subobject is zero sized. =
That being zero sized means that the object shares its identity shall effec=
tively lose its identity among any other subobjects of its own type within =
the same non-zero sized containing object.</p>
<p>That is, rather than declaring it to be an unfortunate bug, we embrace i=
t as a feature. As such, we <em>actively forbid</em> implementations from a=
llowing different zero sized instances at the same level from having differ=
ent addresses. <code>multiple::ns1</code> <em>must</em> have the same addre=
ss as <code>multiple::ns2</code>.</p>
<p>This also means that there is only one such object. This creates an inte=
resting problem with object lifetime and construction/destruction calls. In=
deed, any per-member compiler-generation function call.</p>
<p>On the one hand, if there is only one such object, then there should onl=
y be one constructor and one destructor call. But there are two member vari=
ables, and having only one call would be weird. Indeed, the two objects cou=
ld be subobjects of different zero sized subobjects.</p>
<p>What's worse is that, if the user declares a copy constructor or assignm=
ent operator, they will have to list both objects in their member initializ=
er. If they declare an assignment operator, they have to list both objects.=
</p>
<p>So the only logical alternative here is that you <em>have</em> to call t=
he constructor multiple times. In which case, the object model has to chang=
e.</p>
<p>In order for zero sized subobjects of any kind to work, we declare that =
many objects of different types live in the same region of storage. In orde=
r for two zero sized subobjects of the same type to live in the same region=
 of storage, we have to declare that, since they have no value representati=
on, then a memory location can conceptually hold any number of zero sized s=
ubobjects of any type. Even if they are the same type.</p>
<p>As such, constructing one member subobject begins its lifetime. Construc=
ting a second begins its lifetime. This leaves you with two objects of the =
same type in the same location of memory.</p>
<h3 id=3D"only-stateless-types-can-be-zero-sized-subobjects">Only stateless=
 types can be zero sized subobjects</h3>
<p>With this solution, we make the assumption that, if a user declares that=
 a type is <code>stateless</code>, then they are making a strong claim abou=
t this type. Namely that losing identity is perfectly valid, that it is rea=
sonable for two objects of the same type to have the same address and live =
in the same memory.</p>
<p>So we solve the problem by only permitting zero sized subobjects of type=
s that are themselves declared stateless. That way, we know that the user e=
xpects such types to alias. This also means that stateless types can only h=
ave subobjects of other stateless types (lest they be able to lose identity=
 as well).</p>
<p>This solves the unique identity problem by forcing the user to explicitl=
y specify when it is OK to lose unique identity. However, it fails to solve=
 the general problem of people using EBO as a means for having a zero sized=
 subobject. They will continue to do so, as the set of <code>stateless</cod=
e> declared objects will always be smaller than the set of PST types that q=
ualify for EBO.</p>
<h3 id=3D"explicitly-forbid-the-problem-cases">Explicitly forbid the proble=
m cases</h3>
<p>The unique identity problem arises because two zero sized subobjects of =
the same type exist within the same containing type in such a way that they=
 could alias. So we can simply forbid that. This is a special case rule, ve=
ry similar to the one that prevents types from being standard layout if the=
ir first NSDM is the same type as one of their empty base classes.</p>
<p>We declare that an object which has a zero sized subobject that can alia=
s with another instance of that type is il-formed. This would be recursive,=
 up the subobject containment hierarchy. That's the general idea, but the c=
urrent rule takes note of the fact that a zero sized object cannot alias wi=
th other objects of its type if it is contained in the exact same object de=
claration.</p>
<h3 id=3D"not-quite-zero-sized">Not quite zero sized</h3>
<p>Standard layout rules effectively side-step the unique identity problem =
by decreeing that a type which uses a base class more than once or has a ba=
se class that is the same type as its first NSDM (recursively) is not stand=
ard layout. And therefore, you no longer are guaranteed to have base classe=
s not disturb the type's layout.</p>
<p>So one possible solution is to make <code>zero_sized</code> behave like =
standard layout: the declaration is a <em>request</em>, not a requirement. =
If the type cannot build a layout to fulfill that request, then the compile=
r is allowed to insert arbitrary space to make it work out, so that all pot=
entially aliasing subobjects have the same size.</p>
<p>To make this useful however, it has to have the same reliability that st=
andard layout provides to empty layout base classes. So there would have to=
 be some system of rules which, if the user follows them, will guarantee th=
at the layout will not be impacted by any <code>zero_sized</code> subobject=
s. If it's not reliable, people will just go back to using standard layout =
types with EBO.</p>
<p>Indeed, it could simply be standard layout rules, with some additions. T=
hat is, building a class for which zero sized subobjects could alias means =
that the type is not standard layout. After all, people frequently do rely =
on zero sized base class subobjects, even when their types are not standard=
 layout.</p>
<p>The final rule of standard layout would thus become this. For the prospe=
ctive type <code>T</code>:</p>
<p>Form a collection of subobject declaration in <code>T</code>, consisting=
 of:</p>
<ul>
<li>All member declared <code>zero_sized</code>, if they are not <code>stat=
eless</code></li>
<li>All base class subobjects, if they are not <code>stateless</code></li>
<li>The first non-zero sized NSDM (if it is an array, then the first elemen=
t)</li>
</ul>
<p>These rules are to be applied recursively for each type of these subobje=
cts.</p>
<p>The type <code>T</code> is not standard layout if, within this collectio=
n, there are two or more subobjects with the same type.</p>
<p>Note that this rule explicitly exempts types declared <code>stateless</c=
ode>. Such types are intended to be able to alias, so their presence cannot=
 break standard layout.</p>
<p>This rule ensures that it is safe to assign the memory location of zero =
sized subobjects to the same location of their containing type. In non-stan=
dard layout cases, implementations may have to give the empty class storage=
 to ensure that it does not alias.</p>
<p>If the user wants a hard error if a type cannot satisfy the <code>zero_s=
ized</code> requirement, they can apply <code>static_assert(is_standard_lay=
out_v&lt;T&gt;);</code> wherever they wish.</p>
<p>This also means that we will not strictly need <code>zero_sized(auto)</c=
ode> syntax. Since <code>zero_sized</code> is a request rather than a requi=
rement, applying it to non-empty layout types is not a compile error. It is=
 just a request which could not be fulfilled.</p>
<p>While I personally dislike this solution (mainly because it makes <code>=
zero_sized</code> a suggestion rather than failing when it can't work), it =
does have the effect of having a rule that is comprehensive. The rule for s=
tandard layout types is simple and reasonable, covering existing base class=
 cases as well as the new zero sized case. It allows stateless types to ali=
as, while allowing the user to know when a zero sized type will be zero siz=
ed. At the same time, compilers have the freedom to add padding or even use=
 existing padding to avoid aliasing.</p>
<h3 id=3D"only-zero-sized-types-can-lose-identity">Only zero sized types ca=
n lose identity</h3>
<p>This is effectively a combination of some of the previous ideas. The des=
ign in this paper uses this solution, as specified with the <a href=3D"#uni=
que_rule">unique identity rule</a>.</p>
<p>For all PST-but-not-stateless types, we apply a rule that forbids possib=
le unique identity violations. However, if the type is declared <code>state=
less</code>, then we know that the writer of the type has deliberately chos=
en to accept that the type lacks identity, so we permit them to be used wit=
hout restriction.</p>
<p>The current unique identity rule is quite conservative, leaving out situ=
ations where zero sized subobjects cannot alias:</p>
<pre><code>struct empty {};
struct alpha {zero_sized empty e;};
struct beta {zero_sized empty e;};

struct first
{
    alpha a;
    alpha b;    //Legal and no aliasing
    beta c;     //Not legal but no aliasing
};</code></pre>
<h1 id=3D"potential-issues">Potential issues</h1>
<h2 id=3D"the-unknown">The Unknown</h2>
<p>One of the most difficult aspects of dealing with any system like this i=
s that plays with C++'s fundamental object model in new and complex ways. A=
s such, the wording for this needs to be quite precise and comprehensive, l=
est we introduce subtle bugs into the standard.</p>
<p>A good spec doctor needs to be involved with the standardization of this=
 feature.</p>
<h1 id=3D"alternative-designs-explored">Alternative Designs Explored</h1>
<p>There has been many alternatives towards achieving the same ends. Every =
such alternative has to deal with 2 fundamental rules of the C++ object mod=
el:</p>
<ol style=3D"list-style-type: decimal">
<li>Objects are defined by a region of storage.</li>
<li>Two different object instances have different regions of storage.</li>
</ol>
<p>This current proposal is designed to avoid changes to rule #1. Stateless=
 subobjects in this proposal still have a non-zero size. Instead, changes t=
o rule #2 are made to permit such subobjects to be able to not disturb the =
layout of their container.</p>
<p>Other alternatives take a different approach to dealing with these rules=
..</p>
<h2 id=3D"magic-standard-library-wrapper-type">Magic standard library wrapp=
er type</h2>
<p><a href=3D"https://groups.google.com/a/isocpp.org/d/msg/std-proposals/sA=
dqngl8pew/xCjHCLpuAAAJ">This idea</a> is focused on just the specific case =
of having empty classes potentially take up no space in their containing cl=
asses.</p>
<p>It would essentially declare a standard library type that is, in the con=
text of this proposal, something like this:</p>
<pre><code>template&lt;typename T&gt;
zero_sized(auto) struct allow_zero_size : public T {...};</code></pre>
<p>It is a wrapper which, when used as an NSDM, will not take up any space =
in its containing object if the given type is empty. And if it is not, then=
 it will.</p>
<p>The theoretical idea behind this is that it doesn't require new syntax. =
And in that proposal, <code>allow_zero_size</code> would not be forbidden f=
rom being in arrays or any of the other forbearances that this proposal for=
bids stateless types from.</p>
<p>This makes the behavior of such a type rather more difficult to specify.=
 The standard would still need to have changes to allow subobojects which t=
ake up no space to work, since users have to be able to get pointers/refere=
nces to them and the like. Once that work is done, exactly how you specify =
that a subobject takes up no space does not really matter.</p>
<h2 id=3D"zero-sized-by-type-declaration">Zero sized by type declaration</h=
2>
<p>An older version of this idea permitted statelessness in a form similar =
to what is specified here. But that design evolved from the needs of inner =
classes and mixins, where it was solely on an implementation of a type to b=
e used for a specific purpose.</p>
<p>As such, in that design, a class was declared stateless. Once this was d=
one, that type could only be used to declare objects as direct subobject of=
 another type, and they would be implicitly zero sized. Since both inner cl=
asses and mixins are intended for only those uses, that was not a significa=
nt limitation.</p>
<p>The problem with this solution is that it does not solve the general zer=
o sized problem outlined in the <a href=3D"#motivation">motivation</a> sect=
ion.</p>
<h1 id=3D"changelist">Changelist</h1>
<h2 id=3D"from-pre-release-v4">From pre-release v4:</h2>
<ul>
<li>Renamed &quot;possibly-stateless type&quot; to &quot;empty layout type&=
quot;.</li>
<li>Stateless subobjects renamed to zero sized subobjects, to avoid confusi=
on with stateless types. This also better reflects the standard wording.</l=
i>
<li><code>zero_sized</code> and <code>stateless</code> declarations no long=
er can have general conditions. They are either forced or <code>(auto)</cod=
e>.</li>
<li>Added another alternative examined in the unique identity rule case: al=
lowing zero sized types to affect the layout of the object if the compiler =
cannot avoid object aliasing.</li>
</ul>
<h2 id=3D"from-pre-release-v3">From pre-release v3:</h2>
<ul>
<li>Applying one possible solution for the unique identity problem.</li>
<li>Adjusting design to accept the fact that <code>is_empty</code> is not e=
nough to ensure viability for statelessness. We really need <code>is_empty<=
/code> and <code>is_standard_layout</code>, thus provoking the need for PST=
..</li>
<li>Because stateless types mean something much stronger, it is now express=
ly forbidden to have subobjects of stateless types that are not stateless t=
ypes.</li>
</ul>
<h2 id=3D"from-pre-release-v2">From pre-release v2:</h2>
<ul>
<li>Added details about the empty object identity problem, as well as a num=
ber of potential solutions.</li>
</ul>
<h2 id=3D"from-pre-release-v1">From pre-release v1:</h2>
<ul>
<li>Clarified that stateless types act like regular empty types in all case=
s except when declared as direct subobjects of classes.</li>
<li>Explicitly noted that the alignment of stateless subobjects will be res=
pected by their containers.</li>
</ul>
<h1 id=3D"standard-notes">Standard notes:</h1>
<ul>
<li>[intro.object]/5-6: Explains how base classes can be zero sized. Also e=
xplains that different instances of the same type must have distinct addres=
ses.</li>
<li>[basic.lval]/10: The &quot;strict aliasing rule&quot;.</li>
<li>[class]/4: States that member subobjects cannot be zero sized. But expl=
icitly does not mention base classes.</li>
</ul>
<h1 id=3D"acknowledgments">Acknowledgments</h1>
<p>From the C++ Future Discussions forum:</p>
<ul>
<li>Avi Kivity</li>
<li>A. Jo=C3=ABl Lamotte, who's original thread on <a href=3D"https://group=
s.google.com/a/isocpp.org/d/msg/std-proposals/u35GIuJECcQ/Yorc58iiBwAJ">Inl=
ine Classes</a> was the seed for this idea.</li>
<li>Vicente J. Botet Escriba</li>
<li>Matt Calabrese</li>
<li>Andrew Tomazos</li>
<li>Matthew Woehlke</li>
<li>Bengt Gustafsson</li>
<li>Thiago Macieira, who initially identified the unique identity problem.<=
/li>
</ul>
<div class=3D"footnotes">
<hr />
<ol>
<li id=3D"fn1"><p>This is mainly to avoid confusion. If you declare a state=
less member, you expect it to be zero sized. So forbidding constructs where=
 that is not possible is reasonable.<a href=3D"#fnref1">=E2=86=A9</a></p></=
li>
</ol>
</div>
</body>
</html>

------=_Part_3607_1704225841.1469502506237
Content-Type: text/x-markdown; charset=UTF-8; name="Stateless Subobjects.md"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename="Stateless Subobjects.md"
X-Attachment-Id: feb6afea-1420-4abb-8b69-3f58aa2b43ae
Content-ID: <feb6afea-1420-4abb-8b69-3f58aa2b43ae>

% Zero sized Subobjects and Stateless Types, pre-release v5
%
% July 25, 2016

This proposal specifies the ability to declare member and base class subobj=
ects which do not take up space in the objects they are contained within. I=
t also allows the user to define classes which will always be used in such =
a fashion.

# Motivation and Scope {#motivation}

C++'s object model does not allow for the size of any complete type to be 0=
.. Every complete object must take up a certain region of storage.

However, the object model does permit the layout of a class to allocate no =
storage to a particular subobject. The standard even effectively mandates t=
his through standard layout rules: an empty, standard layout base class in =
a standard layout type must effectively have zero storage within the class =
it is a base class of. This does not affect the `sizeof` the base class sub=
object, as stated in [expr.sizeof]/2.

This proposal is to expand these zero sized subobjects in two ways. First, =
to enforce that a particular base class subobject will be zero sized. Secon=
d, and most importantly, to enforce that a particular *member* subobject wi=
ll be zero sized.

One of the primary use cases for this feature is as follows.

There are many times when a user wants to use a class that the user provide=
s, but the class may or may not have members. If it is has no members, then=
 the class using should not grow in size simply due to the presence of an e=
mpty subobject. After all, an object which has no members does not need to =
take up space to do its job.

To avoid this, users will frequently use standard layout rules and the empt=
y base optimization to allow them to have access to a zero sized subobject:

=09template<typename Alloc>
=09struct DataBlock : public Alloc
=09{
=09};

In this case, if `Alloc` is empty, then so long as `DataBlock` follows stan=
dard layout rules, the user is guaranteed that `DataBlock` is no larger tha=
n it would have been if `Alloc` were not empty. Even if it does not follow =
standard layout, the compiler is free to make the empty base `Alloc` zero s=
ized.

There are problems with such a use. If `Alloc` is not empty (and `DataBlock=
` does not require that it is), and `Alloc` declares a virtual function, it=
 is possible that `DataBlock<Alloc>` will accidentally override that virtua=
l function. Or not quite override it and cause a compile error. Whereas if =
`Alloc` were a non-static data member, this could easily be avoided.

Equally importantly, this use of `Alloc` is simply not how a user would nat=
urally write this class. Inheritance is supposed to model an "is a" relatio=
nship. Yet conceptually, `DataBlock` is not an `Alloc`; it *has* an `Alloc`=
.. `DataBlock` uses inheritance, not to properly model the relationship, but=
 simply as an optimization tool, to keep the class from growing unnecessari=
ly.

Another problem arises if `Alloc` is *not* empty and if `DataBlock` wanted =
to have members of its own. In that case, `DataBlock<Alloc>` could not be a=
 standard layout type, since both itself and the base class have NSDMs. If =
we had instead made `Alloc` an actual member, then whether `DataBlock` is s=
tandard layout depends on whether `Alloc` is.

The intent of this proposal is to permit, among other things, classes like =
`DataBlock` to declare `Alloc` as a non-static data member. And if `Alloc` =
is empty, then `DataBlock` can use syntax to make the `Alloc` NSDM take up =
no space in `DataBlock`'s layout.

This would also be recursive, so that if `Alloc` had no NSDMs, and `DataBlo=
ck<Alloc>` had no NSDMs besides the `Alloc` member, then `DataBlock<Alloc>`=
 would also be considered an empty type. And therefore, some other type cou=
ld use it in a zero sized fashion.

This proposal also pushes forth the concept of a "stateless type". This is =
a type which, when declared as a subobject, will always be used in a zero s=
ized fashion. But it means something more. It represents a type which funda=
mentally lacks identity. The C++ object model requires every instance of an=
 object to have a distinct address. But most empty types don't care about h=
aving a distinct address.

For the purposes of this proposal, stateless types are used as a way to get=
 around a fundamental limitation of C++'s object model. Future proposals ho=
wever can build upon this to add more functionality.

# Design {#design}

Note: The following syntax is entirely preliminary. This proposal is not we=
dded to the idea of introducing new keywords or somesuch. This syntax is he=
re simply for the sake of understanding how the functionality should genera=
lly be specified. The eventual syntax could be a contextual keyword like `f=
inal` and `override`, or it could be something else entirely.

## Empty layout type

The `is_empty` trait is true for a class which has no NSDMs in itself or an=
y of its base classes, as well as no virtual functions or inheritance. It i=
s also restricted to class types.

However, that alone does not mean that the type can functionally be zero si=
zed within a subobject. An empty type can have the same base class instance=
 multiple times. The C++ object model does not allow two object instances o=
f the same type to have the same address. So the layout of this "empty" typ=
e will have to be larger than a truly empty type. This means that the type =
cannot be zero sized when used as a subobject.

To be able to be zero sized, a type must be empty as well as standard-layou=
t, since the standard-layout rules restrict types from having the same base=
 class instance multiple types.

Thus, we define the concept of an empty layout type. An empty layout type i=
s a class for which both `std::is_empty` and `std::is_standard_layout` are =
true.

The standard library will need a traits class `is_empty_layout` to detect i=
f a type has an empty layout.

## Zero sized subobojects

A non-static data member subobject of a type can be declared to be zero siz=
ed with the following syntax:

=09struct Data
=09{
=09=09zero_sized Type val;
=09};
=09
A base class subobject of a type can be declared to be zero sized with the =
following syntax:

=09struct Data : public zero_sized Type
=09{
=09=09...
=09};

For these declarations to be well-formed, `Type` must be an empty layout ty=
pe.

`zero_sized` cannot be applied to:

* Members of a `union` class
* base classes that use `virtual` inheritance
* Member subobjects that are arrayed
* Variables that are not declared as non-static data members

The `zero_sized` property can be conditional, based on the type being decla=
red, using this syntax:

=09template<typename Alloc>
=09struct DataBlock
=09{
=09=09zero_sized(auto) Alloc a;
=09};

The subobject `a` will be a zero sized member only if its type is empty lay=
ouyt.

Classes which contain zero_sized subobjects, directly or indirectly, are su=
bject to the [Unique Identity Rule](#unique_rule). Class declarations that =
violate the unique identity rule are il-formed.

## Zero-sized behavior {#zero_sized_behavior}

Zero sized subobjects have no effect on the layout or size of their contain=
ing object. Similarly, the rules for standard layout types ignore the prese=
nce of any zero sized subobjects (a class can be standard layout with publi=
c zero sized members and private non-zero sized members). And thus, two cla=
sses can be layout compatible even if they differ by the presence of zero s=
ized subobjects.

Zero sized subobjects otherwise have the same effects on their containing t=
ypes as regular subobjects do. For example, a zero sized subobject can caus=
e its container to not be trivially copyable, if it has a non-trivial copy =
constructor (even though the object by definition has no state to copy).

The definition of "empty class" (per `std::is_empty`) must now be expanded.=
 The rules for an empty class are:

* Non-union class
* No virtual functions
* No virtual base classes
* No non-empty base classes (zero sized base subobjects are, by definition,=
 empty)
* No non-zero sized NSDMs

In all other ways, except where detailed below, a zero sized subobject work=
s identically to a non-zero sized one. zero sized subobjects are initialize=
d and destroyed just as if they were not zero sized. Zero sized subobjects =
undergo copy and move construction and assignment along with all other subo=
bjects (though they will likely not be doing much). In particular, zero siz=
ed subobjects are still members/base classes of the types that contain them=
, so aggregate initialization of members (and bases) will still have to tak=
e them into account:

=09struct foo {};

=09struct aggregate
=09{
=09  zero_sized foo f;
=09  int b;
=09};

=09//It may have no state, but `f` must still be initialized.
=09aggregate agg =3D {{}, 4};

Note that the alignment of a zero sized subobject will still impact the ali=
gnment of the containing class. A `zero_sized` member declaration can inclu=
de an `alignas` specifier as well.

## Stateless types

A type can be declared to have the stateless property:

=09stateless class ClassName : BaseClasses
=09{
=09=09...
=09};

The `stateless` keyword must be consistently associated with any forward de=
clarations for stateless types.

=09class ClassName;  //Not a stateless type.

=09stateless class ClassName  //Compiler error: you told me it wasn't state=
less before.
=09{
=09};

And vice-versa.

A stateless class definition is ill-formed if the class is not a empty layo=
ut type. However, a stateless class definition is also il-formed if it has =
any subobjects that are not themselves of stateless types.

The size of a stateless class is not affected by being stateless. Therefore=
, the size of a stateless class shall be no different from the size of any =
other empty layout class.

The statelessness of a type can be conditional:

=09template<typename T>
=09stateless(auto) struct Foo : public T {};

This will declare `Foo` to be a stateless type if all of its subobjects are=
 also stateless. Note that, even if `stateless(auto)` is used, the class de=
finition must not have array member subobjects.

The fact that a class is declared stateless has no effect on most uses of t=
hat type. When using the type to create an object that is not a subobject o=
f another type, everything behaves normally.Therefore, you can heap allocat=
e arrays of stateless classes, and they will function just like any heap al=
located array of PST classes. You can declare an automatic or global variab=
le of a stateless type, and it will behave as any PST class (note: implemen=
tations are free to optimize such objects to take up no space if possible, =
but they are not required to do so).

However, when a stateless class is used to declare a direct subobject of an=
other type, that subobject declaration will implicitly be zero sized. It is=
 perfectly valid to explicitly specify `zero_sized` on a member/base class =
of a stateless type as well.

Zero sized subobjects created through stateless classes are exempt from the=
 [unique identity rule](#unique_rule).

Declaring an array of a stateless type as an NSDM is il-formed. Stateless t=
ypes may not be used as members of a union.[^1]

The standard library will need a traits class to detect if a type is statel=
ess, since this does restrict the type's use.

## Stateless anonymous types

Statelessness can be applied to anonymous types as well:

=09stateless(auto) struct
=09{
=09=09Data d;
=09} varName;

The `stateless` property applies to the struct declaration, not the variabl=
e. As such, `decltype(varName)` will be a stateless type if `Data` is a sta=
teless type. Such declarations can only be made as non-static data members.

## Unique identity rule {#unique_rule}

Any class which contains (directly or indirectly) a subobject which is zero=
 sized is subject to the unique identity rule. The goal of this rule is to =
ensure that each object within a struct has [unique identity](#identity) wh=
ile fulfilling the layout requirements of zero-sized subobjects. This rule =
is as follows.

For every subobject, recursively, of a class `T`, if that subobject is decl=
ared `zero_sized`, and that subobject is not of a `stateless` type, then lo=
ok through `T`'s subobjects, recursively. If there is another subobject of =
that type (whether zero sized or not), and that subobject is created from a=
 different subobject *declaration*, then `T` violates the unique identity r=
ule.

Note that "different subobject declaration" means the following:

    struct empty {};
=09struct holder { zero_sized empty e; };
=09
=09struct data
=09{
=09=09holder h1;
=09=09holder h2;
=09};
=09
`h2.e` does not cause a violation of the unique identity rule. The reason b=
eing that `h1.e` and `h2.e` both come from the same declaration: the defini=
tion of `holder`.

By contrast, these would be illegal:

=09struct data2
=09{
=09=09holder h1;
=09=09empty e2; //Same type as `h1::e`, but different declaration.
=09};
=09
=09struct data2a
=09{
=09=09holder h1;
=09=09zero_sized holder h2; //Same type as `h1`, but different declaration.
=09};
=09
Do note that the identity rule works even for derived classes and arrays of=
 types that contain zero_sized subobjects:

=09struct data3 : public holder
=09{
=09=09holder h2;
=09=09holder hs[40];
=09};
=09
This works because of standard layout rules. Or rather, because `data3` is =
*not* standard layout. Because of that, `data3::holder` and `data::h2` must=
 have distinct addresses. And therefore, their zero_sized subobjects will a=
s well.

This does forbid many cases that theoretically could work. It may be possib=
le to come up with more complex forms of this rule that allow zero sized su=
bobjects to be used in more places. But with added complexity comes the cha=
nce to get something wrong.

### Once more with complexity

This is a more complex definition of the rule that would permit users more =
valid cases.

Let us define the concept of a "potentially aliasing subobject." A subobjec=
t is potentially aliasing if the address of that subobject *might* alias wi=
th the containing object itself. This requires casting a wide net, since im=
plementations are explicitly allowed to vary. For some type `T`, the subobj=
ects which are potentially aliasing are:

* If `T` is a union, then all of its NSDMs
* If `T` is not a union,=20
=09* All zero sized NSDMs
=09* All (non-virtual?) base class subobjects
=09* The first non-zero sized NSDM of each access class. If the first such =
member is an array, then only the first array element is considered

This rule applies recursively. For each subobject, its potentially aliasing=
 subobjects are added to the list.

A type violates the unique identity rule if there is a potentially aliasing=
 subobject declared `zero_sized`, who's type is *not* declared `stateless`,=
 and there is another potentially aliasing subobject of the same type (whet=
her declared `zero_sized` or not).

This permits the following case, which was illegal under the first definiti=
on:

=09struct data2
=09{
=09=09holder h1;
=09=09empty e2;
=09};

This is now legal because `e2` is not potentially aliasing and therefore wi=
ll not be considered. However, if it `empty` had been a base class or `e2` =
was declared stateless, then it would violate the rule.

Consider these:

=09struct data4a : holder
=09{
=09=09holder h1;
=09=09empty e2;
=09};
=09
=09struct data4b : holder
=09{
=09=09empty e2;
=09=09holder h1;
=09};

Neither of these are legal. The base class `holder` has a zero sized `empty=
` NSDM. So whether `holder` or `empty` is first, there is a potential alias=
 with the base class.

Note that C++'s general forbearance of aliasing with the same type prevents=
 `data4a` from being a genuine case of aliasing. Even though `holder` is an=
 empty class, `data4a` isn't standard layout because the base class is the =
same type as the first NSDM. So the standard requires that the base class a=
nd the first member have different addresses. Thus, the two zero sized memb=
ers of each cannot alias. So this is a false positive.

# Design rationale

A number of restrictions on the use of zero sized subobjects come from impl=
ementation restrictions or the needs of basic C++ assumptions about types. =
This section goes into detail about some of the rationales for the design d=
ecisions, as well as alternatives that were discarded.

## Memory locations

C++'s object model already permits the concept of zero sized subobjects ([i=
ntro.object]/5-6). At present, these are only applied to base classes ([cla=
ss]/4), and only *required* under standard layout rules ([class]/7). Such z=
ero sized subobjects are permitted to have the same address as their contai=
ning object.

We simply want to piggy-back off of these rules. However, this my cause pro=
blems with strict aliasing rules, as we would have two unrelated types whic=
h have the same address (two of the same type with the same address is cove=
red under the [unique identity rule](#identity)).

So we might need an alteration to [basic.lval]/10 to permit zero sized subo=
bjects to work. It would be an added exemption to the list of exemptions th=
ere.

I do not believe that this is an implementation problem, since zero sized s=
ubobojects by their very nature have no state to access. As such, the speci=
fic address of their `this` pointer is irrelevant (again, pursuant to uniqu=
e identity).

Given that the address of a zero sized subobject could be any valid address=
 within the object, should we declare that the address is the address of it=
s containing object? This would match with the address for zero sized base =
class subobjects.

Implementation-wise, the difficulty will be in changing how types are laid =
out. That is, modifying ABIs to allow member subobjects that have no size a=
nd enforcing EBO even when it might otherwise have not been performed.

The behavior of the *user* converting pointers/references between two unrel=
ated zero sized subobjects should still be undefined.

## Arrays of zero sized objects

This design expressly forbids the declaration of zero sized member subobjec=
ts that are arrayed. The reason for this has to do with pointer arithmetic.

In C++, the following should be perfectly valid for any type `T`, regarldes=
s of where the array of `T` is declared:

=09T t[5];
=09T *first =3D &t[0];
=09T *last =3D first + 5;
=09assert(sizeof(T) * 5 =3D=3D last - first);

The whole point of a zero sized subobject is that it does not take up space=
 within another type. If the array above were a member of another type, thi=
s code still ought to work. But, since `sizeof(T)` is non-zero, that means =
that those values have to take up space somewhere. Each pointer has to be v=
alid.

Under non-array conditions, the pointer to a zero sized subobject could alw=
ays have the same address as its container (recursively, to the last non-ze=
ro sized container). Adding 1 to any such pointer will still be a valid add=
ress; this is required because any object can be considered an array of 1 v=
alue ([expr.add]/4). If the containing class is an empty class with a size =
of 1, then adding one to a zero sized member's pointer is no less valid tha=
n adding 1 to the container's address.

When dealing with an array, this is not necessarily the case. If the array =
of zero sized objects has a count larger than 1, there is no guarantee that=
 adding a number larger than 1 will result in a valid address for the purpo=
ses of iteration.

Several alternatives were considered:

1. Declare that `sizeof` for zero sized subobjects is zero. I am not nearly=
 familiar enough with the C++ standard to know the level of horrors that th=
is would unleash, but I can imagine that it's very bad. It would also make =
it impossible to have a distinction between zero sized subobjects and state=
less types, as the `sizeof` can be applied to a pointer to the object, whic=
h cannot know if the object it points to is a zero sized subobject.

2. Declare that zero sized subobjects which are arrayed will still take up =
space as though they were not declared `zero sized`.

3. Forbid declaring arrays of zero sized subobjects altogether.

Option 1 is probably out due to various potential issues. #2 seems tempting=
, but it makes the use of `zero_sized T arr[4];` something of a lie. Earlie=
r designs used #3, then switched to #2. But the current design goes back to=
 #3 for an important reason.

In the current design, it is the *use* of a type which is zero sized. Becau=
se this can be applied to any empty layout class at its point of use, if a =
user wants to be able to use an empty layout class in a non-zero-sized way =
within a class (such as an array), then they simply do not declare the clas=
s to be `stateless`.

## Trivial copyability

Trivial copyability is another area that can be problematic with zero size =
subobjects. We explicitly forbid trivial copying into a base class subobjec=
t of another class ([basic.types]/2).

Similarly, we must explicitly forbid trivial copying into zero sized subobo=
jects. Trivial copying *from* a zero sized subobject should be OK. Though t=
his is only "OK" in the sense that the program is not ill-formed or that th=
ere us undefined behavior. The value copied is undefined, but that doesn't =
matter, since you could only ever use that value to initialize a type that =
is layout compatible with an PST class. Namely, another PST class. And PST =
classes have no value.

## offsetof

`offsetof` will obviously not be affected by zero sized subobject members o=
f another type. However, if `offsetof` is applied to a zero sized subobject=
, what is the result?

If we define the pointer to a zero sized subobject to be the same as its co=
ntainer, then the `offsetof` should be 0. Otherwise, the `offsetof` should =
be undefined but within the region of storage for its container.

## Unique identity problem {#identity}

An empty type has no valid data; it has no real value representation. But u=
nder current C++ rules, it does have one important piece of state: itself.

The present rules of C++ allow a number of cases where the addresses of two=
 object instances are equal. This involves subobjects: base classes can hav=
e the same address as the derived class. The first member subobject often h=
as the address of the containing class. And for standard layout types, empt=
y base classes will have the same address as the first member, which will h=
ave the same address as the containing class.

Despite all of this, there is one inviolate rule with subobject layout: for=
 any two distinct objects of the same dynamic type `T`, they will have *dif=
ferent addresses*. Because of this rule, an empty type can grant itself sta=
te by using its `this` pointer as a unique identifier, with the state being=
 stored and accessed externally to the object instance.

However, in order to make a subobject zero sized, in order for it to not af=
fect the layout of its containing type, we have to accept that the pointer =
value could alias with another object. And therefore, the address of one in=
stance of a type could alias with the address of another instance. If the t=
ype were written to use external state based on its `this` pointer (or if c=
ode using that type were written expecting it), then we would break that ex=
pectation and therefore potentially that code.

As such, blindly applying `zero_sized` to any empty layout type could have =
unpleasant consequences. Various alternatives were considered to solve this=
 problem; the solution proposed here is the last one presented, and is impl=
emented in the [design section above](#design).

### Ignore the problem

One solution considered was to just ignore the problem. The scope of the pr=
oblem is such that it would only happen if:

1. The user has created an empty layout type that gains state state through=
 its object identity.

2. The type is used as a zero sized subobject.

3. The type is used as a zero sized subobject which aliases with another in=
stance of itself within the same object.

Users who do #1 can defend themselves against #2 simply by declaring that t=
he type has an NSDM of type `char`. Alternatively, we can define special sy=
ntax to allow users to actively prevent a PST from being used as a stateles=
s subobject.

### There is no problem

Another solution examined was to redefine the problem. It only occurs when =
two or more zero sized subobjects of the same type can alias each other wit=
hin the same containing object. So we can simply declare that, when that ha=
ppens, the objects are *not distinct objects*. One is an alias for the othe=
r.

As such, we have identity only of the ultimate non-zero sized containing su=
bobject. If the user expects (given the above example) `multiple::ns1` and =
`multiple::ns2` to be different objects, then the user is simply wrong to t=
hink so.

This sounds like ignoring the problem, but it really is different. In the p=
revious suggestion, it's a corner case. With this suggestion, we conceptual=
ly re-evaluate what it means to declare that a subobject is zero sized. Tha=
t being zero sized means that the object shares its identity shall effectiv=
ely lose its identity among any other subobjects of its own type within the=
 same non-zero sized containing object.

That is, rather than declaring it to be an unfortunate bug, we embrace it a=
s a feature. As such, we *actively forbid* implementations from allowing di=
fferent zero sized instances at the same level from having different addres=
ses. `multiple::ns1` *must* have the same address as `multiple::ns2`.

This also means that there is only one such object. This creates an interes=
ting problem with object lifetime and construction/destruction calls. Indee=
d, any per-member compiler-generation function call.

On the one hand, if there is only one such object, then there should only b=
e one constructor and one destructor call. But there are two member variabl=
es, and having only one call would be weird. Indeed, the two objects could =
be subobjects of different zero sized subobjects.

What's worse is that, if the user declares a copy constructor or assignment=
 operator, they will have to list both objects in their member initializer.=
 If they declare an assignment operator, they have to list both objects.

So the only logical alternative here is that you *have* to call the constru=
ctor multiple times. In which case, the object model has to change.

In order for zero sized subobjects of any kind to work, we declare that man=
y objects of different types live in the same region of storage. In order f=
or two zero sized subobjects of the same type to live in the same region of=
 storage, we have to declare that, since they have no value representation,=
 then a memory location can conceptually hold any number of zero sized subo=
bjects of any type. Even if they are the same type.

As such, constructing one member subobject begins its lifetime. Constructin=
g a second begins its lifetime. This leaves you with two objects of the sam=
e type in the same location of memory.

### Only stateless types can be zero sized subobjects

With this solution, we make the assumption that, if a user declares that a =
type is `stateless`, then they are making a strong claim about this type. N=
amely that losing identity is perfectly valid, that it is reasonable for tw=
o objects of the same type to have the same address and live in the same me=
mory.

So we solve the problem by only permitting zero sized subobjects of types t=
hat are themselves declared stateless. That way, we know that the user expe=
cts such types to alias. This also means that stateless types can only have=
 subobjects of other stateless types (lest they be able to lose identity as=
 well).

This solves the unique identity problem by forcing the user to explicitly s=
pecify when it is OK to lose unique identity. However, it fails to solve th=
e general problem of people using EBO as a means for having a zero sized su=
bobject. They will continue to do so, as the set of `stateless` declared ob=
jects will always be smaller than the set of PST types that qualify for EBO=
..

### Explicitly forbid the problem cases

The unique identity problem arises because two zero sized subobjects of the=
 same type exist within the same containing type in such a way that they co=
uld alias. So we can simply forbid that. This is a special case rule, very =
similar to the one that prevents types from being standard layout if their =
first NSDM is the same type as one of their empty base classes.

We declare that an object which has a zero sized subobject that can alias w=
ith another instance of that type is il-formed. This would be recursive, up=
 the subobject containment hierarchy. That's the general idea, but the curr=
ent rule takes note of the fact that a zero sized object cannot alias with =
other objects of its type if it is contained in the exact same object decla=
ration.

### Not quite zero sized

Standard layout rules effectively side-step the unique identity problem by =
decreeing that a type which uses a base class more than once or has a base =
class that is the same type as its first NSDM (recursively) is not standard=
 layout. And therefore, you no longer are guaranteed to have base classes n=
ot disturb the type's layout.

So one possible solution is to make `zero_sized` behave like standard layou=
t: the declaration is a *request*, not a requirement. If the type cannot bu=
ild a layout to fulfill that request, then the compiler is allowed to inser=
t arbitrary space to make it work out, so that all potentially aliasing sub=
objects have the same size.

To make this useful however, it has to have the same reliability that stand=
ard layout provides to empty layout base classes. So there would have to be=
 some system of rules which, if the user follows them, will guarantee that =
the layout will not be impacted by any `zero_sized` subobjects. If it's not=
 reliable, people will just go back to using standard layout types with EBO=
..

Indeed, it could simply be standard layout rules, with some additions. That=
 is, building a class for which zero sized subobjects could alias means tha=
t the type is not standard layout. After all, people frequently do rely on =
zero sized base class subobjects, even when their types are not standard la=
yout.

The final rule of standard layout would thus become this. For the prospecti=
ve type `T`:

Form a collection of subobject declaration in `T`, consisting of:

* All member declared `zero_sized`, if they are not `stateless`
* All base class subobjects, if they are not `stateless`
* The first non-zero sized NSDM (if it is an array, then the first element)

These rules are to be applied recursively for each type of these subobjects=
..

The type `T` is not standard layout if, within this collection, there are t=
wo or more subobjects with the same type.

Note that this rule explicitly exempts types declared `stateless`. Such typ=
es are intended to be able to alias, so their presence cannot break standar=
d layout.

This rule ensures that it is safe to assign the memory location of zero siz=
ed subobjects to the same location of their containing type. In non-standar=
d layout cases, implementations may have to give the empty class storage to=
 ensure that it does not alias.

If the user wants a hard error if a type cannot satisfy the `zero_sized` re=
quirement, they can apply `static_assert(is_standard_layout_v<T>);` whereve=
r they wish.

This also means that we will not strictly need `zero_sized(auto)` syntax. S=
ince `zero_sized` is a request rather than a requirement, applying it to no=
n-empty layout types is not a compile error. It is just a request which cou=
ld not be fulfilled.

While I personally dislike this solution (mainly because it makes `zero_siz=
ed` a suggestion rather than failing when it can't work), it does have the =
effect of having a rule that is comprehensive. The rule for standard layout=
 types is simple and reasonable, covering existing base class cases as well=
 as the new zero sized case. It allows stateless types to alias, while allo=
wing the user to know when a zero sized type will be zero sized. At the sam=
e time, compilers have the freedom to add padding or even use existing padd=
ing to avoid aliasing.

### Only zero sized types can lose identity

This is effectively a combination of some of the previous ideas. The design=
 in this paper uses this solution, as specified with the [unique identity r=
ule](#unique_rule).

For all PST-but-not-stateless types, we apply a rule that forbids possible =
unique identity violations. However, if the type is declared `stateless`, t=
hen we know that the writer of the type has deliberately chosen to accept t=
hat the type lacks identity, so we permit them to be used without restricti=
on.

The current unique identity rule is quite conservative, leaving out situati=
ons where zero sized subobjects cannot alias:

=09struct empty {};
=09struct alpha {zero_sized empty e;};
=09struct beta {zero_sized empty e;};

=09struct first
=09{
=09=09alpha a;
=09=09alpha b;=09//Legal and no aliasing
=09=09beta c;=09=09//Not legal but no aliasing
=09};

# Potential issues

## The Unknown

One of the most difficult aspects of dealing with any system like this is t=
hat plays with C++'s fundamental object model in new and complex ways. As s=
uch, the wording for this needs to be quite precise and comprehensive, lest=
 we introduce subtle bugs into the standard.

A good spec doctor needs to be involved with the standardization of this fe=
ature.

# Alternative Designs Explored

There has been many alternatives towards achieving the same ends. Every suc=
h alternative has to deal with 2 fundamental rules of the C++ object model:

1. Objects are defined by a region of storage.
2. Two different object instances have different regions of storage.

This current proposal is designed to avoid changes to rule #1. Stateless su=
bobjects in this proposal still have a non-zero size. Instead, changes to r=
ule #2 are made to permit such subobjects to be able to not disturb the lay=
out of their container.

Other alternatives take a different approach to dealing with these rules.

## Magic standard library wrapper type

[This idea](https://groups.google.com/a/isocpp.org/d/msg/std-proposals/sAdq=
ngl8pew/xCjHCLpuAAAJ) is focused on just the specific case of having empty =
classes potentially take up no space in their containing classes.

It would essentially declare a standard library type that is, in the contex=
t of this proposal, something like this:

=09template<typename T>
=09zero_sized(auto) struct allow_zero_size : public T {...};

It is a wrapper which, when used as an NSDM, will not take up any space in =
its containing object if the given type is empty. And if it is not, then it=
 will.

The theoretical idea behind this is that it doesn't require new syntax. And=
 in that proposal, `allow_zero_size` would not be forbidden from being in a=
rrays or any of the other forbearances that this proposal forbids stateless=
 types from.

This makes the behavior of such a type rather more difficult to specify. Th=
e standard would still need to have changes to allow subobojects which take=
 up no space to work, since users have to be able to get pointers/reference=
s to them and the like. Once that work is done, exactly how you specify tha=
t a subobject takes up no space does not really matter.

## Zero sized by type declaration

An older version of this idea permitted statelessness in a form similar to =
what is specified here. But that design evolved from the needs of inner cla=
sses and mixins, where it was solely on an implementation of a type to be u=
sed for a specific purpose.

As such, in that design, a class was declared stateless. Once this was done=
, that type could only be used to declare objects as direct subobject of an=
other type, and they would be implicitly zero sized. Since both inner class=
es and mixins are intended for only those uses, that was not a significant =
limitation.

The problem with this solution is that it does not solve the general zero s=
ized problem outlined in the [motivation](#motivation) section.

# Changelist

## From pre-release v4:
* Renamed "possibly-stateless type" to "empty layout type".
* Stateless subobjects renamed to zero sized subobjects, to avoid confusion=
 with stateless types. This also better reflects the standard wording.
* `zero_sized` and `stateless` declarations no longer can have general cond=
itions. They are either forced or `(auto)`.
* Added another alternative examined in the unique identity rule case: allo=
wing zero sized types to affect the layout of the object if the compiler ca=
nnot avoid object aliasing.

## From pre-release v3:
* Applying one possible solution for the unique identity problem.
* Adjusting design to accept the fact that `is_empty` is not enough to ensu=
re viability for statelessness. We really need `is_empty` and `is_standard_=
layout`, thus provoking the need for PST.
* Because stateless types mean something much stronger, it is now expressly=
 forbidden to have subobjects of stateless types that are not stateless typ=
es.

## From pre-release v2:
* Added details about the empty object identity problem, as well as a numbe=
r of potential solutions.

## From pre-release v1:
* Clarified that stateless types act like regular empty types in all cases =
except when declared as direct subobjects of classes.
* Explicitly noted that the alignment of stateless subobjects will be respe=
cted by their containers.

# Standard notes:

* [intro.object]/5-6: Explains how base classes can be zero sized. Also exp=
lains that different instances of the same type must have distinct addresse=
s.
* [basic.lval]/10: The "strict aliasing rule".
* [class]/4: States that member subobjects cannot be zero sized. But explic=
itly does not mention base classes.

# Acknowledgments

From the C++ Future Discussions forum:

* Avi Kivity
* A. Jo=C3=ABl Lamotte, who's original thread on [Inline Classes](https://g=
roups.google.com/a/isocpp.org/d/msg/std-proposals/u35GIuJECcQ/Yorc58iiBwAJ)=
 was the seed for this idea.
* Vicente J. Botet Escriba
* Matt Calabrese
* Andrew Tomazos
* Matthew Woehlke
* Bengt Gustafsson
* Thiago Macieira, who initially identified the unique identity problem.

[^1]: This is mainly to avoid confusion. If you declare a stateless member,=
 you expect it to be zero sized. So forbidding constructs where that is not=
 possible is reasonable.
------=_Part_3607_1704225841.1469502506237--

.


Author: Matthew Woehlke <mwoehlke.floss@gmail.com>
Date: Tue, 2 Aug 2016 15:39:50 -0400
Raw View
On 2016-07-16 06:55, Bjorn Reese wrote:
> Can the stateless subobjects access the member variables of the parent
> class?

Not in and of themselves. You're thinking of inner classes. An inner
class may be stateless, but a stateless member is not necessarily an
inner class.

--
Matthew

--
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/57A0F706.4040909%40gmail.com.

.