Primitives in instanceof and patterns
Brian Goetz
brian.goetz at oracle.com
Tue Sep 13 18:14:52 UTC 2022
I'm going to try and address these points *for the benefit of everyone
else*. (Note to Remi only: this is not an invitation to continue the
back and forth, as doing so would likely be unconstructive unless you
have something either (a) radically new that no one has thought of yet
and/or (b) something that is so obviously right and compelling that I
will immediately weep with embarrassment for how wrong I was. That's
the bar at this point. I get that you hate this feature. You've made
that manifestly clear. But unless you have some significantly new light
to shed on it, it is unconstructive to just keep banging this drum, and
you are creating an environment where others feel less comfortable
sharing their thoughts, which is unacceptable.)
> 1) having a primitive pattern doing a range check is useless because
> this is rare that you want to do a range check + cast in real life,
> How many people have written a code like this
>
> int i = ...
> if (i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE) {
> byte b = (byte) i;
> ...
> }
>
> It's useful when you write a bytecode generator without using an
> existing library, ok, but how many write a bytecode generator ?
> It should not be the default behavior for the primitive type pattern.
This argument stems from a misunderstanding of what we are trying to
accomplish here. Yes, it is correct that `case byte b` is not something
everyone will use (I have written this many times, though I admit this
is probably unusual.) But that's not the point of this exercise; the
point of the exercise is uniformity, in part because the lack of
uniformity is complexity, and in part we want to offer new semantic
symmetries that programmers can count on. You are trying to tinker at
the margins, asking if each conversion carries its weight; that's a
recipe for creating new, ad-hoc complexity surface. Sometimes that's
the right move, and sometimes it is unavoidable, but there is such an
obviously correct interpretation of primitive instanceof here -- "would
a cast to this type be safe" -- that it would be an unforced error to
opt for the ad-hoc complexity just because you can't imagine using it
that often.
If I have a record:
record R(int x) { }
I can construct it with
new R(aShort)
but under the strict semantics of primitive type patterns, I cannot
deconstruct it with
case R(short s) { }
which would ask: "could this record have come from a constructor
invocation `new R(s)`". And this is gratuitously different than the
correspond case with reference widening:
record S(Object o) { }
S s = new S("foo");
if (s instanceof S(String ss)) { ... }
Further, I take objection to your continued characterization of this as
a "range check", as this is a mischaracterization as well as minimizing
what is going on. Casting subsumes boxing and unboxing as well as
widening and narrowing, so a more correct characterization would be
"could I cast this without loss or error to a short". Which applies not
only to wider and narrower types, but to types like Short and Object.
Just like `instanceof` for reference types, which asks whether the type
could be cast to another type. And without creating a new context for
what is allowable.
Not only is the term "useless" unconstructive, but it is not even the
right measure. The bar here is not "would people use it a lot." We're
making the language simpler by making it more uniform. To say "let's
gratuitously knock some of the boxes out of the cast matrix because I
can't imagine using them" only makes the language more complicated.
> 2) It's also useless because there is no need to have it as a pattern,
> when you can use a cast in the following expression
> Person person = ...
> switch(person) {
> // instead of
> // case Person(double age) -> foo(age);
> // one can write
> case Person(int age) -> foo(age); // widening cast
> }
Same argument (also you got your example backwards). I get that you
think its fine to have to do this, but it is yet another gratuitous
asymmetry between aggregation and destructuring that confuses people
about how destructuring works. Why can you pass an int or a double to
`new Person`, but could only take an `double` out? Whereas with
Object/String, you could take either out?
Again, this is gratuitous complexity, which I think is rooted in your
unwillingness to let go of "instanceof means subtype." Sorry, it
doesn't any more (but it means something that generalizes it.)
> 3) when you read a conditional primitive patterns, you have no idea
> what is the underlying operation until you go to the declaration
> (unlike the code just above).
This is the same complaint you had in the past about partial and total
nested patterns. As I've said, I understand why you find it
uncomfortable ("action at a distance"), but we evaluated the pros and
cons extensively already, and we made our decision. There's no reason
to reopen it here, nor are the considerations any different in this case.
> 4) if we change the type pattern to be not just about subtyping, we
> should revisit the JLS to avoid to have too many different semantics.
This is FUD, implying that we are going to have to reexamine
everything. I don't buy it. Many of the things that lean on subtyping
today are just ... subtyping. And the things that have conversions
involving primitives already lean on conversions and contexts.
By way of concrete example, you raised the question about covariant
overrides. Which was a good example, and which I appreciate, but I wish
you would have raised it differently.
A constructive way to raise this would be: "Do we also want to reexamine
covariant overrides to use castability (or some other criteria) rather
than subtyping?"
An unconstructive way to raise this would be: "This feature is bad, look
at the problems you are creating for covariant overrides, everything
will have to be reexamined."
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-observers/attachments/20220913/c0174124/attachment-0001.htm>
More information about the amber-spec-observers
mailing list