Bridging the divide between unconditionalitty and exhaustiveness for ReferenceType patterns

Brian Goetz brian.goetz at oracle.com
Thu Oct 12 13:22:16 UTC 2023


Backing up, what you're saying here is that both total and partial 
reference type patterns have opinions about nullity (null-accepting and 
null-rejecting, respectively), and while these may be reasonable 
defaults, you would like to be able to "override" these defaults.  I 
sympathize.

There was much discussion about whether we needed a separate way of 
saying something like (T|Null), or T-but-not-null, explicitly.  As you 
can imagine, many syntaxes were proposed, but they were all unsatisfying 
because (a) they ceded much syntactic real estate (and therefore much 
mindshare) to a distinction that was small, and often ignorable, and (b) 
if we ever got nullity control in the future (T! and T?), these ad-hoc 
pattern forms would look permanently silly.





On 10/11/2023 7:25 PM, Steffen Yount wrote:
> Amber devs,
>
> For the Patterns available to us in Java 21 it has been noted that:
> 1) TypePatterns match unconditionally, that is to say they are "null 
> matching". Meanwhile RecordPatterns at most match exhaustively leaving 
> null valued ReferenceTypes in the remainder, that is to say 
> RecordPatterns are "non-null matching" or "instance matching".
>
> 2) It's the "null hostility" of the "switch" and "instanceof" 
> operators that prevents TypePatterns from matching/dominating the null 
> values there:
>
> * In the case of "switch" a null valued ReferenceType selector 
> expression will cause a NullPointerException to be thrown by the 
>  switch operator unless the "case null" switch label has been declared 
> in its switch block.
>
> * In the case of "instanceof" evaluation, when the the 
> RelationalExpression is null valued, null is interpreted semantically 
> as "not an instance" and thus also as "not an instance of" the 
> ReferenceType (or Pattern) found to the right of the "instanceof" keyword.
>
>
> This dichotomy between TypePatterns and RecordPatterns illustrates a 
> gap in current pattern matching coverage wherein we cannot match null 
> vs non-null vs nullable for non-record ReferenceTypes.
>
> I would love to see this gap closed.
>
> In JEP 455, I can see there's a lot of work going into making Patterns 
> work well with PrimitiveTypes, is anyone looking into making Patterns 
> work better with these ReferenceTypes?
>
> What are your thoughts on closing this pattern matching coverage gap 
> and maybe implementing something like the following:
>
> The current Java 21 Pattern definitions look like
>
> Pattern:
>     TypePattern
>     RecordPattern
>
> The TypePattern part could be deconstructed and extended giving new 
> Pattern definitions that look more like:
>
> Pattern:
>     PrimitivePattern (PrimitiveType)
>     RecordPattern    (non-null valued record ReferenceType)
>     InstancePattern  (non-null valued ReferenceType)
>     NullPattern      (null valued ReferenceType)
>     ReferencePattern (ReferenceType)
>
> Notes:
> 1) The InstancePattern matching a ReferenceType T and the NullPattern 
> matching that same ReferenceType T are complements of each other and 
> exhaustively cover the match space of a ReferencePattern matching that 
> same ReferenceType T
>
> 2) The ReferencePattern matching a ReferenceType T dominates both a 
> NullPattern and a InstancePattern matching that same ReferenceType T
>
> 3) The RecordPattern matching a record ReferenceType T for a Record 
> declared with a zero-arg constructor exhaustively covers the 
> InstancePattern matching that same ReferenceType T
>
> 4) The InstancePattern matching a record ReferenceType T dominates a 
> RecordPattern matching that same ReferenceType T
>
> Sample of proposed Pattern notation:
>
> match-only Pattern notation:
>     PrimitivePattern: int
>     RecordPattern:    Bat(_,_)
>     InstancePattern:  Bat()
>     NullPattern:      null
>     ReferencePattern: Bat
>
> match+projection Pattern notation:
>     PrimitivePattern: int ii
>     RecordPattern:    Bat(_,_) bb
>     InstancePattern:  Bat() bb
>     NullPattern:      null bb
>     ReferencePattern: Bat bb
>
> (When matched, the pattern's named variables are projected into the 
> appropriate declaration scope)
>
> Proposed Pattern appearance and idiomatic familiarity:
>     PrimitivePattern: Resembles a local PrimitiveType variable declaration
>     RecordPattern:    Resembles an "all-args" constructor call for a 
> record ReferenceType
>     InstancePattern:  Resembles a "no-args" constructor call for a 
> ReferenceType
>     NullPattern:      Resembles a ReferencePattern where the 
> ReferenceType has been replaced with the NullLiteral
>     ReferencePattern: Resembles a local ReferenceType variable declaration
>
> Does this notation feel good and Java-ish to you? Have you already got 
> something better figured out? Your thoughts?
>
> Thanks for your consideration,
> -Steffen
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20231012/6c0141a5/attachment.htm>


More information about the amber-dev mailing list