User model stacking: current status

Brian Goetz brian.goetz at oracle.com
Thu Jun 16 19:21:42 UTC 2022


Quick observation: the default value of `String!` is less dangerous to 
allow free, because its "null", and the user can already freely make 
nulls.   Whereas the default value of `Instant` is not something the 
user can get their hands on, if they can't observe fields of type 
`Instant.val` during initialization.  So the problem may be less severe 
for B1.

On 6/16/2022 3:16 PM, Kevin Bourrillion wrote:
> On Wed, Jun 15, 2022 at 12:01 PM Brian Goetz <brian.goetz at oracle.com> 
> wrote:
>
>     OK, let's say for sake of argument that "well, that's what you
>     opted into."  Non-atomic means no one can count on cross-field
>     integrity; don't select non-atomic if you have invariants to
>     protect.  OK fine.  And let's flip over to what T! means.
>
>     Let's say that T! is a restriction type; it can take on the values
>     of T, except for those prohibited by the restriction "t != null". 
>     So, what is the default value of `String!`?
>
>
> I'd like to slightly rephrase your question to "What do we do when we 
> need a default value /for/ `String!`", because I don't like the 
> framing that suggests that a default value is an inherent property /of 
> a type/ itself. (I've no idea what type theorists would say.)
>
> And we were talking about bucket 2, a "value class with no good 
> default" so I'll substitute `Instant!` instead of `String!` for most 
> of this.
>
> So, what to do when we need a default value for `Instant!`? I guess 
> "just blow up" is a non-option because every field has to start off 
> somewhere. So I guess we have to answer "it's `fromEpochMilli(0)` 
> because it can't be anything else, but we're going to do what we can 
> to prevent its users from depending on that fact." Definitely, making 
> an explicit value type that's nonpublic is a way to do just that. Is 
> there a more surgical way to do it?
>
> One easy way to get surgical is to have OpenJDK just stop worrying 
> about the bad-default-values problem, and let aftermarket static 
> analyzers like ours take up that mantle. We can have an annotation to 
> mark classes like Instant, and we can issue warnings when we see bogus 
> usages (some of which we warn on anyway). In fact, if you do exactly 
> what you're planning (so flip back from Instant! to Instant.val, and 
> give the val type an access modifier), I guess we might end up doing 
> this in Error Prone anyway, so that people can make their value types 
> public safely. That would feel actually totally fine to me. And in the 
> `Instant!` world, there's not much to hang a modifier on, but we 
> wouldn't care if we were doing this checking anyway.
>
> You don't need to explain that "we'd rather release language features 
> that /don't/ need aftermarket tools to use safely", I know it. But it 
> is just a platitude really. I think that any language design 
> expressive enough to users do good things will inevitably be 
> expressive enough to let them do bad things too; static analysis 
> always has a crucial role to play imho. And of course it is always the 
> trio of language/libraries/tools together that drives the user's 
> ultimate experience.
>
> (Now changing back to `String`, a bucket-1 class, I've been expecting 
> it will be much longer before we'd roll out !/? to those types, but 
> when we do, I think your particular question comes out better. "What's 
> the default for `String!` when we absolutely must have one?" Well, 
> when we must we must, so we must commit null pollution. We try to 
> issue enough of the right warnings to live with the fallout. If we 
> ever make a transition like this, we have to level expectations; I'm 
> convinced null pollution will be a part of all of our lives, more so 
> than heap pollution of the generics kind ever was, but I'm also still 
> optimistic that it will still be worth it. You could say that today we 
> live with 100% null pollution...)
>
>
>     For locals, it's pretty clear we don't have to answer, because
>     locals cannot be accessed unless they are DA at the point of
>     access.  But for fields, we have a problem -- and for arrays, a
>     bigger one.  We can try to require that fields have initializers,
>     but there are all sorts of situations in which a field can be read
>     before its initializer runs.
>
>
> ... which situations already lead to bad behavior / puzzlers as it is. 
> We might miss a warning we'd rather have been able to give, but life 
> goes on?
>
>       And arrays are much worse.
>
>
> Arrays in general, or just the one single construction path `new 
> TheType![size]` (or `new TheType.val[size]`)? I would just say please 
> give us new Arrays methods or syntax that create and fill at once, and 
> we'll get busy clamping down on everything else.
>
>
>
>     On 6/15/2022 2:10 PM, Kevin Bourrillion wrote:
>>     On Wed, Jun 15, 2022 at 10:51 AM Brian Goetz
>>     <brian.goetz at oracle.com> wrote:
>>
>>          - If we spelled .val as !, then switching from P[] to P![]
>>         not only prohibits null elements, but changes the layout and
>>         _introduces tearing_.  Hiding tearability behind "non-null"
>>         is likely to be a lifetime subscription to Astonishment
>>         Digest, since 99.9999 out of 100 Java developers will not be
>>         able to say "non-null, oh, that also means I sacrifice
>>         atomicity."
>>
>>
>>     Well, that's what you opted into when you... wait a minute...
>>
>>         The link you probably want to attack is this last one, where
>>         you are likely to say "well, that's what you opted into when
>>         you said `non-atomic`; you just happen to get atomicity for
>>         free with references, but that's a bonus."
>>
>>
>>     Your Kevin's Brain Emulator has gotten pretty decent over time...
>>     check whether the next things it said were these (probably so):
>>
>>     A good clean Basic Conceptual Model For Novices is allowed to
>>     have a bunch of asterisks, of the form "well, in $circumstance,
>>     this will be revealed to be totally false", and that's not always
>>     a strike against the model. How do we discern the difference
>>     between a good asterisk and a bad one? How common the
>>     circumstance; how recognizable as /being/ a special circumstance;
>>     how disproportionate a truth discrepancy we're talking about; etc.
>>
>>     I know I've said this before. If I'm in a class being taught how
>>     this stuff works, and the teacher says "Now unsafe concurrent
>>     code can break this in horrible ways, and in $otherClass you will
>>     learn what's really going on in the presence of data races" ... I
>>     feel fully satisfied by that. I know I won't get away with
>>     playing fast and loose with The Concurrency Rules; I'm not
>>     advanced enough and might never be. (Many people aren't but
>>     /don't /know it, and therein lies the problem, but do we really
>>     have much power to protect such people from themselves?)
>>
>>     I could be wrong, but I suspect this kind of viewpoint might be
>>     more common and respected in the wider world than it is among the
>>     rarefied kind of individuals who join expert groups, no offense
>>     to anyone here meant. You're always going to see all the details,
>>     and you're always going to /want/ to see all the details. The
>>     general public just hopes the details stay out of their way. When
>>     they don't, they have a bad day, but it doesn't mean they were
>>     better served by a complex model that tried to account for
>>     everything.
>>
>>
>>     -- 
>>     Kevin Bourrillion | Java Librarian | Google, Inc. |kevinb at google.com
>
>
>
> -- 
> Kevin Bourrillion | Java Librarian | Google, Inc. |kevinb at google.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/valhalla-spec-observers/attachments/20220616/d800ed7f/attachment-0001.htm>


More information about the valhalla-spec-observers mailing list