----- Original Message ----- > From: "Brian Goetz" <brian.go...@oracle.com> > To: "valhalla-spec-experts" <valhalla-spec-experts@openjdk.java.net> > Sent: Wednesday, April 27, 2022 6:44:01 PM > Subject: User model stacking
> Here’s some considerations for stacking the user model. (Again, please let’s > resist the temptation to jump to the answer and then defend it.) > > We have a stacking today which says: > > - B1 is ordinary identity classes, giving rise to a single reference type > - B2 are identity-free classes, giving rise to a single reference type > - B3 are flattenable identity-free classes, giving rise to both a reference > (L/ref) and primitive (Q/val) type. > > This stacking has some pleasant aspects. B2 differs from B1 by “only one > bit”: > identity. The constraints on B2 are those that come from the lack of identity > (mutability, extensibility, locking, etc.) B2 references behave like the > object references we are familiar with; nullability, final field guarantees, > etc. B3 further makes reference-ness optional; reference-free B3 values give > up the affordances of references: they are zero-default and tearable. This > stacking is nice because it can framed as a sequence of “give up some X, get > some Y”. > > People keep asking “do we need B2, or could we get away with B1/B3”. The main > reason for having this distinction is that some id-free classes have no > sensible default, and so want to use null as their default. This is a > declaration-site property; B3 means that the zero value is reasonable, and use > sites can opt into / out of zero-default / nullity. We’d love to compress > away this bucket but forcing a zero on classes that can’t give it a reasonable > interpretation is problematic. But perhaps we can reduce the visibility of > this in the model. > > The degrees of freedom we could conceivably offer are > > { identity or not, zero-capable or not, atomic or not } x { use-site, > declaration-site } > > In actuality, not all of these boxes make sense (disavowing the identity of an > ArrayList at the use site), and some have been disallowed by the stacking > (some > characteristics have been lumped.) Here’s another way to stack the > declaration: > > - Some classes can disavow identity > - Identity-free classes can further opt into zero-default (currently, B3, > polarity chosen at use site) > - Identity-free classes can further opt into tearability (currently, B3, > polarity chosen at use site) > > It might seem the sensible move here is to further split B3 into B3a and B3b > (where all B3 support zero default, and a/b differ with regard to whether > immediate values are tearable). But that may not be the ideal stacking, > because we want good flattening for B2 (and B3.ref) also. Ideally, the > difference between B2 and B3.val is nullity only (Kevin’s antennae just went > up.) > > So another possible restacking is to say that atomicity is something that has > to > be *opted out of* at the declaration site (and maybe also at the use site.) > With deliberately-wrong syntax: > > __non-id class B2 { } > > __non-atomic __non-id class B2a { } > > __zero-ok __non-id class B3 { } > > __non-atomic __zero-ok __non-id class B3a { } > > In this model, you can opt out of identity, and then you can further opt out > of > atomicity and/or null-default. This “pulls up” the atomicity/tearaiblity to a > property of the class (I’d prefer safe by default, with opt out), and makes > zero-*capability* an opt-in property of the class. Then for those that have > opted into zero-capability, at the use site, you can select .ref (null) / .val > (zero). Obviously these all need better spellings. This model frames > specific > capabilities as modifiers on the main bucket, so it could be considered either > a two bucket, or a four bucket model, depending on how you look. > > The author is in the best place to make the atomicity decision, since they > know > the integrity constraints. Single field classes, or classes with only single > field invariants (denominator != 0), do not need atomicity. Classes with > multi-field invariants do. > > This differs from the previous stacking in that it moves the spotlight from > _references_ and their properties, to the properties themselves. It says to > class writers: you should declare the ways in which you are willing to trade > safety for performance; you can opt out of the requirement for references and > nulls (saving some footprint) and atomicity (faster access). It says to class > *users*, you can pick the combination of characteristics, allowed by the > author, that meet your needs (can always choose null default if you want, just > use a ref.) > > There are many choices here about “what are the defaults”. More opting in at > the declaration site might mean less need to opt in at the use site. Or not. > > (We are now in the stage which I call “shake the box”; we’ve named all the > moving parts, and now we’re looking for the lowest-energy state we can get > them > into.) I really like the clean separation between declaration site and use site, the properties being declared as class properties make more sense to me (for whatever reason, i was able to convince myself that it was the actual model). I like the fact that being tearable is a property that has to be enabled (again at declaration site). But know i want all those knobs :) Rémi