Question about type pattern inside record pattern
Matias Koivikko
matias.koivikko at gmail.com
Fri Feb 6 21:21:06 UTC 2026
The null handling observed here does seem to be according to JLS.
Specifically in §14.30.1 one line reads:
> A type pattern is said to be *null-matching* if it is appears directly in
> the component pattern list of a record pattern with type R, where the
> corresponding record component of R has type U, and the type pattern is
> unconditional for the type U
It's a bit unintuitive, but presumably this exception is made in order to
allow deconstructing nulls out of records.
As for the other issue, it seems like the JLS doesn't really care about
reachability, but rather whether switch rules dominate each other.
The Amount(Number _) rule does not dominate Amount(Object _), even though
they end up with the exact same bytecode because the component type is not
accounted for.
Hope this helps!
- Matias
On Fri, 6 Feb 2026 at 18:23, Red IO <redio.development at gmail.com> wrote:
> This definitely looks wrong. Shouldn't a switch with a pattern matching
> against null either have a case or throw an exception?
> This behavior seems to differs between a top level match and nested record
> pattern match. This doesn't seem intuitive nor intentional to me. Even if
> we say that a _ match arm also includes null which to some extent makes
> sense because even if it is null it at least has to be of type Number. I
> would expect a Double _ arm above to not be taken as the information rather
> it's any subtype of Number is not there.
> But last but not least the Object _ shouldn't compile because it is in
> fact unreachable.
>
> Overall a rather quirky edge case of record pattern matching.
> Again I would expect an exception to be thrown because that's the behavior
> defined in the switch expression.
>
> Great regards
> RedIODev
>
> On Fri, Feb 6, 2026, 17:00 Cay Horstmann <cay.horstmann at gmail.com> wrote:
>
>> Consider this program:
>>
>> record Amount(Number n) {}
>>
>> Integer value(Amount p) {
>> return switch (p) {
>> case Amount(Integer value) -> value;
>> case Amount(Number _) -> -1;
>> case Amount(Object _) -> -2;
>> };
>> }
>>
>> void main() {
>> IO.println(value(new Amount(null)));
>> }
>>
>> It prints -1.
>>
>> I have two questions:
>>
>> 1. Why does it compile? The case Amount(Object _) does not seem to
>> reachable.
>> 2. Why does null match case Amount(Number _) and not one of the other?
>>
>> I tried applying JLS (for Java 25) §14.30, §15.28, and §14.11 but could
>> not figure it out. Where should I look?
>>
>> Thanks,
>>
>> Cay
>>
>> --
>>
>> Cay S. Horstmann | https://horstmann.com
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20260206/25b5c676/attachment.htm>
More information about the amber-dev
mailing list