[patterns] Nullability in patterns, and pattern-aware constructs (again)

Brian Goetz brian.goetz at oracle.com
Fri Jan 10 16:03:30 UTC 2020

I don't want to dive into a design discussion on declared patterns, but 
I think we can resolve most of the nullability issues without doing so.

Like methods, declared patterns are members.  Like methods, they can be 
static or instance.

If they are instance, the target is the receiver, and that surely won't 
work if the receiver is null.  So by definition, instance patterns 
cannot match null.  Let's set that aside.

(Example: an instance pattern is a pattern on a class, like:

     switch (aString) {
         case palindrome(var firstHalf, boolean isOdd): ...

where palindrome is an instance pattern on String.)

Declared patterns have a target type (may want a better name), which for 
an instance pattern is the receiver type, and for a static pattern is 
part of the declaration.  (For example, `Optional.of(var x)` has a 
target type of `<T> Optional<T>`.)

We won't even try to match the pattern unless the match target is of the 
target type for the pattern (it's not an Optional.of(anything) if its 
not an Optional to begin with.)  So we have to do some sort of test 
first -- either instanceof (in which case static pattern will never 
match null, period), or a type pattern match (which would be the more 
principled choice, and would only admit a null through to the 
user-written code if the target type of the static pattern were total on 
the operand of the switch/instanceof.)

So it's already a pretty narrow case where a null would be admitted into 
the user code at all.  Now, the finishing blow: do we really want to ask 
the authors of the `Optional.of(var x)` and `Optional.empty()` patterns 
to have to check their target for null?  That would be creating a 
million new bugs to accommodate a handful of corner cases.

Which brings us back to ...

Only the top (total) and bottom (null constant) patterns match null.  
Guy is happy again.  (And the crowd goes wild.)

On 1/9/2020 10:53 PM, John Rose wrote:
> On Jan 9, 2020, at 7:04 PM, Brian Goetz <brian.goetz at oracle.com> wrote:
>> I guess that means the stuff I said about "only having to look in two places" for null-handling was wrong; any static (declared) pattern could be nullable.  Which brings us back to the place that people didn't like the last time around -- you have to scrutinize the implementations of the patterns associated with all N cases to determine whether this switch will take nulls or not.
> Yeah; I wondered if you’d say that.  This is a problem with methods of any
> kind, isn’t it?  Programmers must always wonder what’s inside any given
> method call.  We have javadoc and @NotNull annotations to help, but it’s
> always going to be difficult.
> That said, library patterns will surely be composable from (or along side)
> more primitive patterns, and we (perhaps) could also require that the
> various pieces and parts of a null-friendly library pattern would visibly
> “let the null in” to the library code, and failing that the null would be
> rejected.
> Straw man:  Declare that all static patterns are non-total, and exclude
> null from them on the same principle as today’s non-total patterns.
> This requires a library pattern to be treated as always non-total.
> Straw man:  Allow static patterns to explicitly mention the “receiver”
> of the match, as an optional precursor pattern.  Key null-transmission
> on whether that precursor pattern is total or not, under today’s rules.
> By precursor pattern I mean the occurrence of the pattern “String”
> in the following straw man syntaxes:
>    // static __Pattern myLibPattern(__MatchTarget Object target, int modes);
>    switch (o) {
>    case myLibPattern(0x42): …
>    case myLibPattern(__MatchTarget String x, 0x42): …
>    case String x & myLibPattern(0x42): …
>    case (String x).myLibPattern(0x42): …  // this looks *really* null hostile!
>    …etc…
>    }
> This depends sensitively on the concrete design of library patterns, but
> I’m assuming the usual connection points of (a) the value being matched,
> (b) the outputs to the match (if any), and (c) additional parameters (“modes”).
> My overall point here is that there are plausible options to keeping the
> null under control, even visibly so.  And we can stack the deck so that letting
> in the null is always accompanied by some telltale signal, not just a tacit
> default.
> I think, when we cross this bridge, we can appeal to some combination
> of documentation, good style, and explicit structure in the case pattern.
> Here’s another example to suggest some various degrees of freedom,
> and some pitfalls:
>    static __Pattern <T> ofClass(
>          __MatchTarget Object x,
>          Class<T> c, boolean nullOK,
>          __MatchResult T x2) {
>      if (c.isInstance(x))  __Match(x2 = c.cast(x));
>      else if (nullOK)  __Match(x2 = null);
>      else  __Fail;
>    }  // (not the real syntax)
>    boolean z = …;
>    Object o = …;
>    switch (o) {
>    case Objects.ofClass(String.class, z, var s): return 1;  //worst case
>    case Objects.ofClass(Number.class, true, var n): return 2;  //RTFJD
>    case Objects.ofClass(List.class, false, var x): return 3;  //ditto
>    default: return 0;  //NPE here???
>    }
>> On 1/9/2020 7:57 PM, John Rose wrote:
>>> We haven’t yet moved on to library-defined patterns (“static
>>> patterns”).  To gaze a bit into the crystal ball:  I think it’s
>>> likely that those will provide a way to express T? using
>>> a library API instead of a language primitive.  We should
>>> defer building out that last 1% of null support either
>>> indefinitely, or until there is a way for libraries to define
>>> their own kinds of patterns.  In the latter case the cost
>>> of adding a nullable pattern is likely to be lower than
>>> the alternatives on the table, since library changes are
>>> always cheaper than language changes.

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

More information about the amber-spec-experts mailing list