Patterns design question: Nulls

Remi Forax forax at
Sat Nov 11 13:20:58 UTC 2017

I'm for Option, given Option 2 is not a real Option 2, see below. 
It's unfortunate that the behavior inside nested patterns is different from the behavior of the switch. As you said, it's the expected semantics and i think it's not a big deal if we do not allow destructuring inside a match ( new Box(t) matches Box(Object o)). 

I believe the old switch and the new switch should work the same way. 
it will be surprising if a kind of switch allow to declare a case null and another kind do not allow it. 

Also about having to put the case null at the top because of the dominance analysis, the compiler can easily recognize case 'null' and remove it from the dominance analysis meaning it can be put an any positions, or we can choose by example that if 'default' as to be the last pattern, case null as to be the one just before. 

As far as a understand, your Option 2 is just 1.b, i.e. the semantics is the same as Option 1 and you introduce a specific behavior if the match is detected as being a type restatement. 
In my opinion, there is a more general question first, do we want to allow type restatement ?, and if the option is yes, then we can decide if we want the null behavior to be the one you propose or not. 

I'm not sure it's a good idea to allow type restatement in switch 
- transforming a switch to an if true seems arcane, if we want a type restatement syntax, why use switch and not another construction (let expression ?), it will be more clear. 
- it goes in the opposite direction of the introduction of 'var' in the language, 'var' hides the type but here we introduce a feature to change the type (more or less) for a part of the code, this make the code harder to read for a feature which seems too arcane. 


> De: "Gavin Bierman" <gavin.bierman at>
> À: "amber-spec-experts" <amber-spec-experts at>
> Envoyé: Vendredi 3 Novembre 2017 11:46:10
> Objet: Patterns design question: Nulls

> Nulls and pattern matching

> The null value is treated somewhat inconsistently in Java; unfortunately pattern
> matching places a fresh focus on these inconsistences. Consider a local
> variable, String s=null; . Currently s instanceof String returns false; whereas
> (String)s succeeds; and further switch (s){ case "Hello": ... } throws a NPE.
> Unfortunately, we need to maintain these behaviours whilst providing a
> consistent story for patterns.

> So far, we have essentially two choices on the table. One based on what might be
> called a pragmatic navigation of existing choices; and another more
> sophisticated one based on static type information. (In what follows, we assume
> a declaration T t = null; is in scope.) Option 1.

> Matches t matches Object o . To keep it consistent with instanceof this must
> return false .

> Switch switch is retconned to not throw a NPE when given a null . However, all
> switches with reference-typed selector expressions are considered to have an
> implicit case null: throw new NullPointerException(); clause as the first
> clause in the switch. If the user supplies a null clause (which means it must
> be a pattern-matching switch ) then this replaces the implicit clause. [An
> alternative to this is to introduce non-null type tests, which we fear would
> quickly become unwieldy.]

> Note that this addresses a problem that has been brought up on the external
> mailing list. Currently:
> static void testSwitchInteger(Integer i) {
>     switch(i) {
>         case 1:  System.out.println("One");   break;
>         default: System.out.println("Other"); break;
>     }
> }
> static void testSwitchNumber(Number i) {
>     switch(i) {
>         case 1:  System.out.println("One");   break;
>         default: System.out.println("Other"); break;
>     }
> }
> testSwitchNumber(null);  // prints "Other"
> testSwitchInteger(null); // NPE

> The Integer case is an old-style switch, so throws an NPE. The Number case is a
> pattern matching case, so without the insertion of an implicit null clause, it
> would actually match the default clause (this is the behaviour of the current
> prototype).

> ASIDE Adding a null clause has an impact on the dominance analysis in pattern
> matching. A null pattern must appear before a type test pattern.

> Nested/Destructuring patterns As discussed earlier, t matches Object o returns
> false. But unfortunately new Box(t) matches Box(Object o) really ought to
> return true. (Both because this is what we feel would be expected, but also to
> be consistent with expected semantics of extractors.) In other words, the
> semantics of matching against null is not compositional. Note also that the
> null value never matches against a nested pattern.

> We might expect a translation to proceed something like the following.
> e matches Box(Object o)
> -> e matches Box &&
>        (e.contents matches null as o || e.contents matches Object o)
> -> e instance Box &&
>        (e.contents == null || e.contents instanceof Object)

> (Note the rarely seen as pattern in the intermediate pattern.) Option 2.

> We can use the static type information to classify pattern matches, which
> ultimately determines how the matching is translated.

> For example:
> if (t matches U u) { // where T <: U
>     ...
> }

> Notice here that the pattern match is guaranteed to succeed as T is a subtype of
> U . We can classify this as a type restatement pattern, and compile it
> essentially to the following
> if (true) {
>     U u = t;
>     ...
> }

> In other words, the expression (o matches U u) succeeds depending on the static
> type of o : if the static type of o is a subtype of U then it evaluates to true
> , even for the value of null . If it is not statically a subtype of U then its
> runtime type is tested as normally, and null would fail.

> ASIDE The choice of null matching also impacts on our reachability analysis. For
> example:
> Integer i = ...;
> switch (i) {
>     case Integer j: {
>         System.out.println(j);
>         break;
>     }
>     default: System.out.println("Something else");
> }
> Is the default case reachable? If the type test matches null then it is
> unreachable, otherwise it is reachable.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the amber-spec-experts mailing list