On Tue, Jun 14, 2022 at 9:17 AM Brian Goetz <[email protected]> wrote:
>
>
> The val type for B2 should not exist at all
>
>
>
> So B2 is really a B3a whose value projection is encapsulated.
>
>
> and here you lost me, .ref and .val are supposed to be projection types not
> classes, at runtime there is only one class.
>
>
> And apparently I have to say this again .... It's fine to not understand what
> is being proposed. If so, ask questions, or think about it for a few days
> before responding. But it's Not OK to jump to dogmatic "should not" /
> "wrong" pronouncements before you understand what is being proposed. That's
> just unhelpful.
>
>
>
> Summary:
>
> class B1 { }
> value class B2 { private class val { } }
> value class B3a { }
> non-atomic value class B3n { }
>
> 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.
>
> It's an orthogonal choice whether the default is "val is private" and "val is
> public".
>
>
> It makes B2.val a reality, but B3 has no sane default value otherwise it's a
> B3, so B2.val should not exist.
>
>
> Let me try explaining again.
>
> All value types have .ref and .val types. They have the properties we've
> been discussing for a long time: ref types are references, and are therefore
> nullable and atomic; val types are direct values, are not nullable, and are
> _not necessarily_ atomic.
>
> We've been describing B2 classes as those with "no good default", but that
> doesn't mean that they can't have a .val type. It means we *can't trust
> arbitrary code to properly initialize a B2.val type.* Once initialized,
> B2.val is fine, and have the benefit of greater flatness. We explored
> language and VM features to ensure B2.val types are properly initialized, but
> that ran into the rocks.
>
> But we can allow the B2 class itself to mediate access to the .val type.
> This has two benefits:
>
> - We can get back some of the benefit of flattening B2.val types
> - Uniformity
>
> Here are two examples of where a B2 class could safely and beneficially use
> B2.val:
>
> value class Rational {
> Rational[] harmonicSeq(int n) {
> Rational.val[] rs = new Rational.val[n];
> for (int i=0; i<n; i++)
> rs[i] = new Rational(1, n);
> return rs;
> }
> }
>
> Here, we've made a _flat_ array of Rational.val, properly initialized it, and
> returned it to the user. THe user gets the benefit of flatness, but can't
> screw it up, because of the array store check. If Rational.val were illegal,
> then no array of rationals could be flat.
And with Rational.val requiring atomic access, we can only flatten it
if the underlying HW supports it (in this case, 2 ints fits nicely in
64bits so we're good). Larger .val's can only be flattened if marked
as "non-atomic" (the B3n case). And because there's no tearing,
handing out the flattened Rational.val[] is safe.
Do I have that right?
--Dan
>
> Similarly, a nestmate could take advantage of packing:
>
> value class Complex {
> value class C3 {
> Complex.val x, y, z;
>
> ...
> }
>
> C3 c3(Complex x, Complex y, Complex z) { return new C3(x, y, z); }
>
> }
>
> C3 gets the benefit of full flattening, which it can do because its in the
> nest; it can share the flattened instances safely with code outside the nest.
>
> (Access control is powerful thing.)
>
>