[External] Foo / Foo.ref is a backward default; should be Foo.val / Foo
Kevin Bourrillion
kevinb at google.com
Mon Apr 25 02:52:50 UTC 2022
Hi,
The current plan for `primitive class Foo` -- to call the value type `Foo`
and the reference type `Foo.ref` -- is causing a few problems that I think
are unnecessary. I've felt for a while now that we are favoring the wrong
default. We should let `Foo` be the reference type and require `Foo.val`
(precise syntax aside) for the value type.
I started to list reasons and came up with more than expected.
1. The option with fewer hazards should usually be the default. Users won't
opt themselves into extra safety, but they will sometimes opt out of it.
Here, the value type is the one that has attendant risks -- risk of a bad
default value, risk of a bad torn value. We want using `Foo.val` to *feel
like* cracking open the shell of a `Foo` object and using its innards
directly. But if it's spelled as plain `Foo` it won't "feel like" anything
at all.
2. In the current plan a `Foo.ref` should be a well-behaved bucket 2
object. But it sure looks like that `.ref` is specifically telling it NOT
to be -- like it's saying "no, VM, *don't* optimize this to be a value even
if you can!" That's of course not what we mean. With the change I'm
proposing, `Foo.val` does make sense: it's just saying "hey runtime, while
you already *might* have represented this as a value, now I'm demanding
that you *definitely* do". That's a normal kind of a thing to do.
3. This change would permit compatible migration of an id-less to primitive
class. It's a no-op, and use sites are free to migrate to the value type if
and when ready. And if they already expose the type in their API, they are
free to weigh the costs/benefits of foisting an incompatible change onto
*their* users. They have facilities like method deprecation to do it with.
In the current plan, this all seems impossible; you would have to fix all
your problematic call sites *atomically* with migrating the class.
4. It's much (much) easier on the mental model because *every (id-less)
class works in the exact same way*. Some just *also* give you something
extra, that's all. This pulls no rugs out from under anyone, which is very
very good.
5. The two kinds of types have always been easily distinguishable to date.
The current plan would change that. But they have important differences
(nullability vs. the default value chief among them) just as Long and long
do, and users will need to distinguish them. For example you can spot the
redundant check easily in `Foo.val foo = ...; / requireNonNull(foo);`.
6. It's very nice when the *new syntax* corresponds directly to the *new
thing*. That is, until a casual developer *sees* `.val` for the first time,
they won't have to worry about it.
7. John seemed to like my last fruit analogy, so consider these two
equivalent fruit stand signs:
a) "for $1, get one apple OR one orange . . . with every orange purchased
you must also take a free apple"
b) "apples $1 . . . optional free orange with each purchase"
Enough said I think :-)
8. The predefined primitives would need less magic. `int` simply acts like
a type alias for `Integer.val`, simple as that. This actually shows that
the whole feature will be easier to learn because it works very nearly how
people already know primitives to work. Contrast with: we hack it so that
what would normally be called `Integer` gets called `int` and what normally
gets called `Integer.ref` or maybe `int.ref` gets called `Integer` ... that
is much stranger.
What are the opposing arguments?
--
Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/valhalla-spec-experts/attachments/20220424/c7b9401c/attachment.htm>
More information about the valhalla-spec-experts
mailing list