[External] : Re: On tearing
John Rose
john.r.rose at oracle.com
Mon May 16 21:46:23 UTC 2022
On 27 Apr 2022, at 9:50, Brian Goetz wrote:
> …This whole area seems extremely prone to wishful thinking; we hate
> the idea of making something slower than it could be, that we convince
> ourselves that “the user can reason about this.” Whether or not
> it is “too big a leap”, I think it is a bigger leap than you are
> thinking.
>
>> For me, we should make the model clear, the compiler should insert a
>> non user overridable default constructor but not more because using a
>> primitive class is already an arcane construct.
>
> This might help a little bit, but it is addressing the smaller part of
> the problem (zeroes); we need to address the bigger problem (tearing).
I think I mostly agree with Remi on this point.
A tearable primitive class (call it T-B3 as opposed A-B3 which is
atomic) can, as you describe, have its invariants broken by races that
have the effect of writing arbitrary (or almost arbitrary) values into
fields at any time.
A regular mutable B1 class has a similar problem, except it can be
defended by a constructor and/or mutator methods that check per-field
values being stored. Let’s look at the simplest case (which is rare
in practice, since it is scary): Suppose a class has public fields
which are mutable. Call such a class a OM-B1 class meaning “open
mutable B1”.
I think that we can (and probably should) address this educational issue
by making T-B3 classes look (somehow) like OM-B1 classes. Then every
bit of training which leads users to be watchful in their use of OM-B1
will apply to T-B3 classes.
How to make T-B3 look like OM-B1? Well, Remi’s idea of a mandated
open constructor gets most of the way there. Mandating that the B3
fields are public is also helpful. (Records kinda-sorta do that, but
through component reader methods.) I truly think those two steps are
enough, to make it clear to an author of a T-B3 that, if a T-B3
container is accessible to untrusted parties, then it is free to take on
any combination of field values at any time. (And I’m using the word
“free” here in the rigorous math sense, as in a free product type.)
A further step to nail down the message that the components are
independently variable would be to provide a reconstructor syntax of
some sort that amounted to an open invitation to (a) take an instance of
the T-B3, (b) modify or replace any or all of its field values, and then
(c ) put it back in the container it came from. By “open” I mean
“public to all comers”, which means that every baseline Java
programmer, who knows about public mutable fields (we can’t cure world
hunger or negligent Java scribblers), will know that, using that syntax,
anybody can write anything into any T-B3 value stored in an unprotected
container. Just like a OM-B1 object. Nothing new to see, and all the
old warnings apply!
We would have to be careful about our messaging about immutability here,
to prevent folks from mistakenly confusing a T-B3 with an immutable B1
(I-B1) or B2 (all of which are truly immutable).
One way to do this, that would be blindingly obvious (and IMO too
blinding), would to (a) allow a `non-final` modifier on fields,
canceling any implicit immutability property, and (b) *require*
`non-final` modifiers on all fields in a T-B3 class. I put this forward
in the service of brainstorming, to show an extreme (too extreme IMO)
way to forcibly advertise the T- in T-B3 classes. But as I said, I
think in practice it will be enough to make T-B3 classes look like OM-B1
classes, which are clearly not immutable, even without a `non-final`
modifier.
>
> I don’t think we have to go so far as to outlaw tearing, but there
> have to be enough cues, at the use and declaration site, that
> something interesting is happening here.
Yes, cues. And my point above, mainly, is that to the extent such cues
are available in the world of OM-B1 classes already, we should make use
of them for T-B3 classes. And where not, such cues should make it
really clear that there is an open invitation (public to untrusted
parties) to make piecemeal edits to the fields of a T-B3 class.
>
>> There is no point to nanny people here given that only experts will
>> want to play with it.
>
> This is *definitely* wishful thinking. People will hear that this is
> a tool for performance; 99% of Java developers will convince
> themselves they are experts because, performance! Developers
> pathologically over-rotate towards whatever the Stack Overflow crowd
> says is faster. (And so will Copilot.) So, definitely no. This
> argument is pure wishful thinking. (I will admit to being
> occasionally tempted by this argument too, but then I snap out of it.)
I’m with Brian on this.
>> But we (the EG) can also fail, and make a primitive class too easy to
>> use, what scare me is people using primitive class just because it's
>> not nullable.
>
> Yes, this is one of the many pitfalls we have to avoid!
>
> This game is hard.
Yep. Removing null for footprint, by moving from B2 to B3, is a normal
thing people will do, but it if also introduces the T- part
(tearability) secretly, that’s probably a lose. Which leads to the
current consideration of tearability as partially independent from the
B2/B3 axis. So B2 XOR B3 = nullability alone, not =
nullability+atomicity.
Separately, I *do* think T-B3 is more likely to be useful than A-B3
(atomic B3), and likewise T-B2 has limited use compared to A-B2. This
is why I’ve been content with the conflation of T-B3 with B3-simple,
for so long.
But, embracing the current conversation, I do think that T-B3 needs to
be *really clearly componentwise mutable*. I think that whether T-B3 is
the default setting of B3 or some further opt-in (from default A-B3 to
T-B3).
And, to summarize, mandated wide-open fields and/or mandated dumb
non-checking constructors are a legitimate way to advertise the
open-ness of T-B3 classes. Then the tearability part is a small
corollary of the Big Story, which is the openness of the fields to all
comers.
A final point: This is why in our last few meetings I keep mentioning
the C++ idea of a `struct`, which is not a non-class, but rather a class
whose defaults are set to be open to all comers. I think if we do a
“struct-like” design for T-B3 we can win.
More information about the valhalla-spec-observers
mailing list