<html><body><div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000"><div><br></div><div><br></div><hr id="zwchr" data-marker="__DIVIDER__"><div data-marker="__HEADERS__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><b>From: </b>"Brian Goetz" <brian.goetz@oracle.com><br><b>To: </b>"daniel smith" <daniel.smith@oracle.com><br><b>Cc: </b>"valhalla-spec-experts" <valhalla-spec-experts@openjdk.java.net><br><b>Sent: </b>Tuesday, June 14, 2022 1:04:39 AM<br><b>Subject: </b>Re: User model stacking: current status<br></blockquote></div><div data-marker="__QUOTED_TEXT__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><font size="4"><font face="monospace">I've done a little more
        shaking of this tree.  It involves keeping the notion that the
        non-identity buckets differ only in the treatment of their val
        projection, but makes a further normalization that enables the
        buckets to mostly collapse away.  <br><br>
        "value class X" means:<br><br>
         - Instances are identity-free<br>
         - There are two types, X.ref (reference, nullable) and X.val
        (direct, non-nullable)<br>
         - Reference types are atomic, as always<br>
         - X is an alias for X.ref<br><br>
        Now, what is the essence of B2?  B2 means not "I hate zeros",
        but "I don't like that uninitialized variables are initialized
        to zero."  It doesn't mean the .val projection is meaningless,
        it means that we don't trust arbitrary clients with it.  So, we
        can make a slight adjustment: <br><br>
         - The .val type is always there, but for "B2" classes, it is
        *inaccessible outside the nest*, as per ordinary accessibility. 
        <br><br>
        This means that within the nest, code that understands the
        restrictions can, say, create `new X.val[7]` and expose it as an
        `X[]`, as long as it doesn't let the zero escape.  This gives B2
        classes a lot more latitude to use the .val type in safe ways. 
        Basically: if you don't trust people with the .val type, don't
        let the val type escape.</font></font></blockquote><div><br></div><div>I don't trust myself with a B2.val.</div><div>The val type for B2 should not exist at all, otherwise any libraries using the reflection can do getClass() on a X.val[] (even typed as a X[]).</div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><font size="4"><font face="monospace"><br><br>
        There's a bikeshed to paint, but it might look something like:<br><br>
            value class B2 {<br>
                private class val { }<br>
            }<br><br>
        or, flipping the default: <br><br>
            value class B3a { <br>
                public class val { }<br>
            }<br><br>
        So B2 is really a B3a whose value projection is encapsulated.  </font></font></blockquote><div><br></div><div>and here you lost me, .ref and .val are supposed to be projection types not classes, at runtime there is only one class.<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><font size="4"><font face="monospace"><br>
        The other bucket, B3n, I think can live with a modifier:<br><br>
            non-atomic value class B3n { }<br><br>
        While these are all the same buckets as before, this feels much
        more like "one new bucket" (the `non-atomic` modifier is like
        `volatile` on a field; we don't think of this as creating a
        different bucket of fields.)</font></font></blockquote><div><br></div><div>yes !<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><font size="4"><font face="monospace"><br>
        Summary:<br><br>
            class B1 { }<br></font></font><font size="4"><font face="monospace"><font size="4"><font face="monospace">    value class B2 { private class val { }
            }<br></font></font>    value class B3a { }<br></font></font><font size="4"><font face="monospace"><font size="4"><font face="monospace">    non-atomic value class B3n { }<br></font></font><br>
        Value class here is clearly the star of the show; all value
        classes are treated uniformly (ref-default, have a val); some
        value classes encapsulate the val type; some value classes
        further relax the integrity requirements of instances on the
        heap, to get better flattening and performance, when their
        semantics don't require it.<br><br>
        It's an orthogonal choice whether the default is "val is
        private" and "val is public".  </font></font></blockquote><div><br></div><div>It makes B2.val a reality, but B3 has no sane default value otherwise it's a B3, so B2.val should not exist.<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div>regards,<br data-mce-bogus="1"></div><div>RĂ©mi<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><font size="4"><font face="monospace"><br><br></font></font><br>
    <div class="moz-cite-prefix">On 6/3/2022 3:14 PM, Brian Goetz wrote:<br>
    </div>
    <blockquote cite="mid:7ca63dd2-401d-4885-dd67-041fc0c17fae@oracle.com">
      
      <font size="4"><font face="monospace">Continuing to shake this
          tree.  <br><br>
          I'm glad we went through the exploration of "flattenable
          B3.ref"; while I think we probably could address the
          challenges of tearing across the null channel / data channels
          boundary, I'm pretty willing to let this one go.  Similarly
          I'm glad we went through the "atomicity orthogonal to buckets"
          exploration, and am ready to let that one go too.  <br><br>
          What I'm not willing to let go of us making atomicity explicit
          in the model.  Not only is piggybacking non-atomicity on
          something like val-ness too subtle and surprising, but
          non-atomicity seems like it is a property that the class
          author needs to ask for.  Flatness is an important benefit,
          but only when it doesn't get in the way of safety.  <br><br>
          Recall that we have three different representation techniques:
          <br><br>
           - no-flat -- use a pointer<br>
           - low-flat -- for sufficiently small (depending on size of
          atomic instructions provided by the hardware) values, pack
          multiple fields into a single, atomically accessed unit.  <br>
           - full-flat -- flatten the layout, access individual
          individual fields directly, may allow tearing.  <br><br>
          The "low-flat" bucket got some attention recently when we
          discovered that there are usable 128-bit atomics on Intel
          (based on a recent revision of the chip spec), but this is not
          a slam-dunk; it requires some serious compiler heroics to pack
          multiple values into single accesses.  But there may be
          targets of opportunity here for single-field values (like
          Optional) or final fields.  And we can always fall back to
          no-flat whenever the VM feels like it.  <br><br>
          One of the questions that has been raised is how similar
          B3.ref is to B2, specifically with respect to atomicity. 
          We've gone back and forth on this.  <br><br>
          Having shaken the tree quite a bit, what feels like the low
          energy state to me right now is:<br><br>
           - The ref type of all on-identity classes are treated
          uniformly; B3.ref and B2.ref are translated the same, treated
          the same, have the same atomicity, the same nullity, etc.  <br>
           - The only difference across the spectrum of non-identity
          classes is the treatment of the val type.  For B2, this means
          the val type is *illegal*; for B3, this means it is atomic;
          for B3n, it is non-atomic (which in practice will mean more
          flatness.)  <br>
           - (controversial) For all types, the ref type is the
          default.  This means that some current value-based classes can
          migrate not only to B2, but to B3 or B3n.  (And that we could
          migrate to B2 today and further to B3 tomorrow.)  <br><br>
          While this is technically four flavors, I don't think it needs
          to feel that complex.  I'll pick some obviously silly
          modifiers for exposition:<br><br>
           - class B1 { }<br>
           - zero-hostile value class B2 { }<br>
           - value class B3 { }<br>
           - tearing-happy value class B3n { }<br><br>
          In other words: one new concept ("value class"), with two
          sub-modifiers (zero-hostile, and tearing-happy) which affect
          the behavior of the val type (forbidden for B2, loosened for
          B3n.)  <br><br>
          For heap flattening, what this gets us is: <br><br>
           - B1 -- no-flat<br>
           - B2, B3.ref, B3n.ref -- low-flat atomic (with null channel)<br>
           - B3 -- low-flat (atomic, no null channel)<br>
           - B3n -- full-flat (non-atomic, no null channel)<br><br>
          This is a slight departure from earlier tree-shakings with
          respect to tearing.  In particular, refs do not tear at all,
          so programs that use all refs will never see tearing (but it
          is still possible to get a torn value using .val and then box
          that into a ref.)<br><br>
          If you turn this around, the declaration-site decision tree
          becomes:<br><br>
           - Do I need identity (mutability, subclassing, aliasing)? 
          Then B1.  <br>
           - Are uninitialized values unacceptable?  Then B2.  <br>
           - Am I willing to tolerate tearing to enable more
          flattening?  Then B3n. <br>
           - Otherwise, B3.  <br><br>
          And the use-site decision tree becomes:<br><br>
           - For B1, B2 -- no choices to make.<br>
           - Do I need nullity?  Then .ref<br>
           - Do I need atomicity, and the class doesn't already provide
          it?  Then .ref<br>
           - Otherwise, can use .val<br><br>
          The main downside of making ref the default is that people
          will grumble about having to say .val at the use site all the
          time.  And they will!  And it does feel a little odd that you
          have to opt into val-ness at both the declaration and use
          sites.  But it unlocks a lot of things (see Kevin's list for
          more): <br><br>
           - The default name is the safest version.  <br>
           - Every unadorned name works the same way; it's always a
          reference type.  You don't need to maintain a mental database
          around "which kind of name is this".<br>
           - Migration from B1 -> B2 -> B3 is possible.  This is
          huge (and more than we had hoped for when we started this
          game.)<br><br>
          (The one thing to still worry about is that while refs can't
          tear, you can still observe a torn value through a ref, if
          someone tore it and then boxed it.  I don't see how we defend
          against this, but the non-atomic label should be enough of a
          warning.)<br><br><br></font></font><br>
      <div class="moz-cite-prefix">On 5/6/2022 10:04 AM, Brian Goetz
        wrote:<br>
      </div>
      <blockquote cite="mid:80ca8334-ebd7-1157-4081-188de9cb240e@oracle.com">In
        this model, (non-atomic B3).ref takes the place of (non-atomic
        B2) in the stacking I've been discussing.  Is that what you're
        saying? <br>
        <br>
            class B1 { }  // ref, identity, atomic <br>
            value-based class B2 { }  // ref, non-identity, atomic <br>
            [ non-atomic ] value class B3 { }  // ref or val, zero is
        ok, both projections share atomicity <br>
        <br>
        If we go with ref-default, then this is a small leap from
        yesterday's stacking, because "B3" and "B2" are both reference
        types, so if you want a tearable, non-atomic reference type,
        saying `non-atomic value class B3` and then just using B3 gets
        you that. Then: <br>
        <br>
         - B2 is like B1, minus identity <br>
         - B3 means "uninitialized values are OK, you get two types, a
        zero-default and a non-default" <br>
         - Non-atomicity is an extra property we can add to B3, to get
        more flattening in exchange for less integrity <br>
         - The use cases for non-atomic B2 are served by non-atomic B3
        (when .ref is the default) <br>
        <br>
        I think this still has the properties I want; I can freely
        choose the reasonable subsets of { identity, has-zero, nullable,
        atomicity } that I want; the orthogonality of non-atomic across
        buckets becomes orthogonality of non-atomic with nullity, and
        the "B3.ref is just like B2" is shown to be the "false friend."
        <br>
        <br>
      </blockquote>
      <br>
    </blockquote>
    <br><br></blockquote></div></div></body></html>