Topic: RFC - Proposal for more uniform initialization of aggregates


Author: Michael Price - Dev <michael.b.price.dev@gmail.com>
Date: Mon, 31 Dec 2012 13:44:34 -0800 (PST)
Raw View
------=_Part_455_18968586.1356990274101
Content-Type: multipart/alternative;
 boundary="----=_Part_456_4382637.1356990274101"

------=_Part_456_4382637.1356990274101
Content-Type: text/plain; charset=ISO-8859-1

I'm looking for informal comments this proposal.  The short description of
the proposal is as follows:

A proposal to slightly relax of the rules for eliding braces from aggregate
initialization in order to make initialization of arrays and class
aggregates more uniform. This change is required in order to support class
aggregate types with a single member subaggregate that behave similarly to
their array counterparts (i.e. <code>std::array</code>).

I'd like to have a revision ready for proper submission to the committee
within the first week of the January 2013.

See the attached .html file for the details. Thanks everyone!

Michael Price
michael.b.price.dev@gmail.com

--




------=_Part_456_4382637.1356990274101
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

I'm looking for informal comments this proposal. &nbsp;The short descriptio=
n of the proposal is as follows:<div><br></div><div>A proposal to slightly =
relax of the rules for eliding braces from aggregate initialization in orde=
r to make initialization of arrays and class aggregates more uniform.&nbsp;=
This change is required in order to support class aggregate types with a si=
ngle member subaggregate that behave similarly to their array counterparts =
(i.e. &lt;code&gt;std::array&lt;/code&gt;).</div><div><br></div><div>I'd li=
ke to have a revision ready for proper submission to the committee within t=
he first week of the January 2013.</div><div><br></div><div>See the attache=
d .html file for the details. Thanks everyone!</div><div><br></div><div>Mic=
hael Price</div><div>michael.b.price.dev@gmail.com</div><div><br></div>

<p></p>

-- <br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />

------=_Part_456_4382637.1356990274101--
------=_Part_455_18968586.1356990274101
Content-Type: text/html; charset=US-ASCII;
 name=cxx-aggregate-defect-proposal.html
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=cxx-aggregate-defect-proposal.html
X-Attachment-Id: db33af7e-b1a9-416e-a4d6-19be36fc6e76

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html>
<head>

  <meta http-equiv="Content-Type" content="text/html;charset=US-ASCII">

<!-- This should replace the style block once it is published somewhere accessible
  <link href="../../base_www/style.hinc" rel="stylesheet" type="text/css" />
-->

  <style type="text/css">

    body { color: #000000; background-color: #FFFFFF; }
    del { text-decoration: line-through; color: #8B0040; }
    ins { text-decoration: underline; color: #005100; }

    p.example { margin-left: 2em; }
    pre.example { margin-left: 2em; }
    div.example { margin-left: 2em; }

    code.extract { background-color: #F5F6A2; }
    pre.extract { margin-left: 2em; background-color: #F5F6A2;
      border: 1px solid #E1E28E; }

    p.function { }
    .attribute { margin-left: 2em; }
    .attribute dt { float: left; font-style: italic;
      padding-right: 1ex; }
    .attribute dd { margin-left: 0em; }

    blockquote.std { color: #000000; background-color: #F1F1F1;
      border: 1px solid #D1D1D1;
      padding-left: 0.5em; padding-right: 0.5em; }
    blockquote.stddel { text-decoration: line-through;
      color: #000000; background-color: #FFEBFF;
      border: 1px solid #ECD7EC;
      padding-left: 0.5empadding-right: 0.5em; ; }

    blockquote.stdins { text-decoration: underline;
      color: #000000; background-color: #C8FFC8;
      border: 1px solid #B3EBB3; padding: 0.5em; }

    table { border: 1px solid black; border-spacing: 0px;
      margin-left: auto; margin-right: auto; }
    th { text-align: left; vertical-align: top;
      padding-left: 0.8em; border: none; }
    td { text-align: left; vertical-align: top;
      padding-left: 0.8em; border: none; }

  </style>

  <title>Uniform initialization for arrays and class aggregate types</title>

</head>

<body>
  <h1>Uniform initialization for arrays and class aggregate types</h1>

  <p>ISO/IEC JTC1 SC22 WG21 N???? = 13-???? - 2013-01-??</p>

  <address>
    Michael Price, michael.b.price.dev@gmail.com
  </address>

  <h2><a name="introduction">Introduction</a></h2>

  <p>
    This document proposes a slight relaxation of the rules for eliding braces from aggregate initialization in order to make initialization of arrays and class aggregates more uniform.
    This change is required in order to support class aggregate types with a single member subaggregate that behave similarly to their array counterparts (i.e. <code>std::array</code>).
  </p>

  <h2><a name="motivation">Motivation and Scope</a></h2>

  <h3><a name="motivation.theoretical">The Theoretical Problem</a></h3>

  <p>
    The C++ Standard defines the behavior for aggregrate initialization using initialization list syntax in section 8.5.1.  It defines two kinds of types as aggregate types: arrays and class that meet certain restrictions.
  </p>

  <p>
    Paragraph 8.5.1.1 reads:
  </p>

  <blockquote class="std"><p>
    An <em>aggregate</em> is an array or a class (Clause 9) with no user-provided constructors (12.1), no <em>brace-or-equal-initializers</em> for non-static data members (9.2), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).
  </p></blockquote>

  <p>
    The remaining paragraphs of 8.5.1 lay out the rules for initialization of these aggregate types.
    The syntax for initializing the two different kinds of aggregate types are uniform for the simple cases, but as complexity grows beyond simple cases, the initialization begins to diverge as shown in the following examples.
  </p>

  <pre class="example">
  <code>int aggr_array[2] = {1, 2};

  struct aggr_t {
      int a;
      int b;
  } instance = {3, 4};</code>
  </pre>

  <p>
    Initializing aggregates with subaggregates of the same kind, is also uniform.
  </p>

  <pre class="example">
  <code>int aggr_array[2][2] = {{1, 2}, {3, 4}};

  struct aggr_t {
      struct {
          int a;
          int b;
      } x, y;
  } instance = {{1, 2}, {3, 4}};</code>
  </pre>

  <p>
    However, when we begin to mix the aggregate types, uniform initialization begins to break down.
  </p>

  <pre class="example">
  <code>struct aggr_t {
      int a;
      int b;
  }  array_of_aggr[2] = {{1, 2}, {3, 4}};

  struct aggr_ex_t {
      int x[2][2];
  };

  aggr_ex_t bad  = {{1, 2}, {3, 4}};      // <em>Error: Too many initializers, see below for details</em>
  aggr_ex_t good = {{{1, 2}, {3, 4}}};</code>
  </pre>

  <p>
    The reason for this is subletly lays in paragraphs 8.5.1.2 and 8.5.1.6.
  </p>

  <p>
    Paragraph 8.5.1.2 reads:
  </p>

  <blockquote class="std"><p>
    When an aggregate is initialized by an initializer list, as specified in 8.5.4, the elements of the initializer list are taken as initializers for the members of the aggregate, in increasing subscript or member order.
    Each member is copy-initialized from the corresponding <em>initializer-clause</em>.
    If the initializer-clause is an expression and a narrowing conversion (8.5.4) is required to convert the expression, the program is ill-formed.
    [ Note: If an <em>initializer-clause</em> is itself an initializer list, the member is list-initialized, which will result in a recursive application of the rules in this section if the member is an aggregate. &mdash; <em>end note</em>]
  </p></blockquote>

  <p>
    Paragraph 8.5.1.6 reads:
  </p>

  <blockquote class="std"><p>
    An <em>initializer-list</em> is ill-formed if the number of <em>initializer-clauses</em> exceeds the number of members or elements to initialize.
  </p></blockquote>

  <p>
    The outer <code>{}</code> pair cause paragraph 8.5.1.2 to apply.
    The first inner <code>{}</code> pair (i.e. <code>{1, 2}</code>) qualify as the <em>initializer-clause</em> for the first member of <code>aggr_ex_t</code>, namely <code>int x[2][2]</code> and is governed by paragraph 8.5.1.10.
    Then the second inner <code>{}</code> pair (i.e. <code>{3, 4}</code>) are considered an <em>initializer-clause</em>, but paragraph 8.5.1.6 applies since there is not another member of <code>aggr_ex_t</code> and the statement is thus ill-formed.
  </p>

  <h3><a name="motivation.practical">The Practical Problem</a></h3>

  <p>
    This limitation in the current standard was discovered during the process of working on a different proposal to extend the standard library <code>std::array</code> type to support more than one dimension.
    It turns out that implementing those changes in a way that does not introduce another type name (e.g. <code>std::narray</code>) might be impossible given the current language.
  </p>

  <h3><a name="motivation.solution">A Possible Solution</a></h3>

  <p>
    The desirable outcome is to be able to elide the braces in the scenario I have presented.
    Currently, paragraph 8.5.1.11 discusses valid brace elsion and the semantics of initialization in those cases.
    I propose that paragraph 8.5.1.11 be modified to also allow brace elision in the case where the members of the aggregate type consist of a single subaggregate member, such that if there are more than one initializer clause, then the semantics should behave as if there had been a <code>{}</code> pair surrounding all initializer clauses at that nesting level.
  </p>

  <p>
    Paragraph 8.5.1.11 currently reads:
  </p>

  <blockquote class="std"><p>
    Braces can be elided in an <em>initializer-list</em> as follows.
    If the <em>initializer-list</em> begins with a left brace, then the succeeding comma-separated list of <em>initializer-clauses</em> initializes the members of a subaggregate; it is erroneous for there to be more <em>initializer-clauses</em> than members.
    If, however, the <em>initializer-list</em> for a subaggregate does not begin with a left brace, then only enough <em>initializer-clauses</em> from the list are taken to initialize the members of the subaggregate; any remaining <em>initializer-clauses</em> are left to initialize the next member of the aggregate of which the current subaggregate is a member.
  </p></blockquote>

  <p>
    The solution presented above is represented in the following example.
  </p>

  <pre class="example">
  <code>struct aggr_ex_t {
      int x[2][2];
  };

  aggr_ex_t still_good = {{{1, 2}, {3, 4}}};

  aggr_ex_t good = {{1, 2}, {3, 4}}; // <em>Behaves as if the</em>
                                     // <em>initializer list had</em>
                                     // <em>been {{{1, 2}, {3, 4}}}</em>

  // <em>Would still be an error per paragraphs 8.5.1.6 and 8.5.1.11 since the</em>
  // <em>initializer-list would be equivalent to {{{1, 2}, {3, 4}, {5, 6}}}</em>
  // <em>and would have too many initialization-clauses.</em>
  aggr_ex_t still_bad =  {{1, 2}, {3, 4}, {5, 6}};</code>
  </pre>

  <h2><a name="impact">Impact On the Standard</a></h2>

  <p>
    These changes would have the affect that some programs that would be ill-formed under the current language would now be well-formed.
    It will not affect programs that are currently well-formed.
    The extent of the changes to the standard document would be constrained to one paragraph only, 8.5.1.11.
  </p>

  <h2><a name="design">Design Decisions</a></h2>

  <p>
    Allowing brace-elision on aggregates with more than one member was considered and rejected as it seems likely to cause difficulties parsing programs that were already well-formed.
  </p>

  <h2><a name="techspec">Technical Specifications</a></h2>

  <p>
    Edit paragraph 8.5.1.11 as follows.
  </p>

  <blockquote class="std"><p>
    Braces can be elided in an <em>initializer-list</em> as follows.
    <ins>If the aggregate object being initialized has a single, subaggregate member, and their is more than a single <em>initializer-clause</em> (in a comma-separated list), then initialization should occur as if there had been a left brace immediately before the first <em>initializer-clause</em> and a right brace immediately after the last <em>initializer-clause</em>.</ins>
    If the <em>initializer-list</em> begins with a left brace, then the succeeding comma-separated list of <em>initializer-clauses</em> initializes the members of a subaggregate; it is erroneous for there to be more <em>initializer-clauses</em> than members.
    If, however, the <em>initializer-list</em> for a subaggregate does not begin with a left brace, then only enough <em>initializer-clauses</em> from the list are taken to initialize the members of the subaggregate; any remaining <em>initializer-clauses</em> are left to initialize the next member of the aggregate of which the current subaggregate is a member.
  </p></blockquote>
  [<b>TODO:</b> I'm a bit worried about confusion arising because of the second sentence beginning at "it is erroneous for there to be more". That would be pursuant to the new text, but I'm not sure of the proper way to phrase it in standard-ese. &mdash;<i>end TODO</i>]

  <p>
    The example attached to paragraph 8.5.1.11 should remain the same. [<b>TODO:</b> I'd like to add an example here, but the current one is already quite lengthy.  Would it make sense instead to have two paragraphs to describe brace elision? &mdash;<i>end TODO</i>]
  </p>

  <h2><a name="acknowledgements">Acknowledgements</a></h2>

  <p>
    I'd like to thank my employer, Perceptive Software, for the allotment of time to work on this proposal and for their incredible support for career advancement in the R&amp;D department.
  </p>

  <p>
    I'd also like to thank my co-workers, Andrew Regier, Chris Sammis, John Drouhard, William Lichtenberger, and Don Gay, who constantly put up with my fascination with this beautiful language
  </p>

</body>
</html>

------=_Part_455_18968586.1356990274101--

.


Author: Beman Dawes <bdawes@acm.org>
Date: Tue, 1 Jan 2013 21:03:49 -0500
Raw View
On Mon, Dec 31, 2012 at 4:44 PM, Michael Price - Dev
<michael.b.price.dev@gmail.com> wrote:
> I'm looking for informal comments this proposal.  The short description of
> the proposal is as follows:
>
> A proposal to slightly relax of the rules for eliding braces from aggregate
> initialization in order to make initialization of arrays and class
> aggregates more uniform. This change is required in order to support class
> aggregate types with a single member subaggregate that behave similarly to
> their array counterparts (i.e. <code>std::array</code>).
>
> I'd like to have a revision ready for proper submission to the committee
> within the first week of the January 2013.
>
> See the attached .html file for the details. Thanks everyone!

In the proposed wording, change "their" to "there" and change "should
occur" to "occurs".

In standardese, "should" is normative encouragement, not an absolute
requirement. Thus "should" is very rarely used in the standard, except
in non-normative notes or examples.

--Beman

--




.