[External] : Re: Primitive type patterns

Brian Goetz brian.goetz at oracle.com
Mon Feb 28 18:08:07 UTC 2022


>
>     So *of course* there's an obvious definition of how `int x`
>     matches against Integer, and its not a question of whether we
>     "define" it that way, its a question of whether we expose the
>     obvious meaning, or suppress it.  I think the arguments in favor
>     of suppression are pretty weak.
>
>
> The strong argument is that instanceof/switch case is about subtyping 
> relationship while assignment is about assignment conversions, trying 
> to blur the lines between the two has already been tried in the past 
> and it results in pain (see below).

This is pretty much assuming your conclusion, and then stating it as 
justification :)

I get it; you would prefer that pattern matching be *only* about 
subtyping.  I understand why you prefer that.  But I think this is 
mostly a "retreat to the comfort zone" thing.

>
> What about ?
>
> Object o =...
> if (o instanceof byte) { ... }
>
> Does it means that o can be a Long ?
>

This is a good question.  (But I know it's also a trap.)  We first have 
to ask about (static) applicability: is the pattern `byte b` applicable 
to Object?  If not, we'll get a compilation error.

My earlier message said:

  - A primitive type pattern `P p` should be applicable to a reference 
target T if T unboxes to P, or T unboxes to a primitive type that can be 
widened to P [ or if T unboxes to a primitive type that can be narrowed 
to P. ]

Does Object unbox to byte?  No.
Does Object unbox to a primitive type that can be widened to byte?  No.
[brackets] Does Object unbox to a primitive type than can be narrowed to 
byte?  No.

How does this square with assignments?  I cannot assign

     byte b = anObject

|  incompatible types: java.lang.Object cannot be converted to byte

If I try this with casting:

    Object o = 0L
    byte b = (byte) o

I get a CCE, because the cast will only convert from Byte.

Now, what if instead of Object, we start with Long?

     Long l = 0L
     if (l instanceof byte b) { ... }

First, applicability: does Long unbox to a primitive type that can be 
narrowed to byte?  Yes!  Long unboxes to long, and long can be narrowed 
to byte.

Then: matching: if the RHS is not null, we unbox, and do a range check.  
(The rules in my previous mail probably didn't get this case perfectly 
right), but 0L will match, and 0xffff will not -- as we would expect.


We could consider pushing this farther, if we liked, but there's a risk 
of pushing it too far, and I think we're already on the cusp of 
diminishing returns.  We could consider `case byte b` against Object to 
match a Byte.  We discussed this, in fact, a few years ago when we 
talked about "what does `case 0` mean" when we were considering constant 
patterns.  (And we concluded in that discussion that the step where we 
basically treat Long as narrowable to Integer was taking it way too 
far.)  So I think the rules I've specified capture (a) the right set of 
tradeoffs of how loose we want to be with regard to boxing/unboxing 
combined with narrowing/widening, subject to (b) the existing decisions 
we've made about assignments.



-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20220228/08840b56/attachment-0001.htm>


More information about the amber-spec-experts mailing list