User model stacking: current status
Brian Goetz
brian.goetz at oracle.com
Fri May 6 14:04:13 UTC 2022
Thinking more about Dan's concerns here ...
On 5/5/2022 6:00 PM, Dan Smith wrote:
> This is significant because the primary reason to declare a B2 rather
> than a B3 is to guarantee that the all-zeros value cannot be created.
This is a little bit of a circular argument; it takes a property that an
atomic B2 has, but a non-atomic B2 lacks, and declares that to be "the
whole point" of B2. It may be that exposure of the zero is so bad we
may eventually want to back away from the idea, but let's come up with a
fair picture of what a non-atomic B2 means, and ask if that's
sufficiently useful.
> This leads me to conclude that if you're declaring a non-atomic B2,
> you might as well just declare a non-atomic B3.
Fair point, but let's pull on this string for a moment. Suppose I want
a null-default, flattenable value, and I'm willing to take the tearing
to get there. So you're saying "then declare a B3 and use B3.ref". But
B3.ref was supposed to have the same semantics as an equivalent B2! (I
realize I'm doing the same thing I just accused you of above -- taking
an old invariant and positiioning it as "the point". Stay tuned.)
Which means either that we lose flattening, again, or we create yet
another asymmetry between B3.ref and B2. Maybe you're saying that the
combination of nullable and full-flat is just too much to ask, but I am
not sure it is; in any case, let's convince ourselves of this before we
rule it out.
Or maybe, what you're saying is that my claim that B3.ref and B2 are the
same thing is the stale thing here, and we can let it go and get it back
in another form. In which case you're positing a model where:
- B1 is unchanged
- B2 is always atomic, reference, nullable
- B3 really means "the zero is OK", comes with .ref and .val, and
(non-atomic B3).ref is still tearable?
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?
class B1 { } // ref, identity, atomic
value-based class B2 { } // ref, non-identity, atomic
[ non-atomic ] value class B3 { } // ref or val, zero is ok, both
projections share atomicity
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:
- B2 is like B1, minus identity
- B3 means "uninitialized values are OK, you get two types, a
zero-default and a non-default"
- Non-atomicity is an extra property we can add to B3, to get more
flattening in exchange for less integrity
- The use cases for non-atomic B2 are served by non-atomic B3 (when
.ref is the default)
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."
More information about the valhalla-spec-observers
mailing list