javapattern-matchingjlsjava-14

How is the scope of pattern variables resolved in java?


I was going through the pattern variables in java. While reading the JLS it mentioned several conditions regarding when a pattern variable is introduced. It mentions -

The analysis relies on the technical term "introduced by", which has the following form:

  • a pattern variable is introduced by an expression when true
  • a pattern variable is introduced by an expression when false
  • a pattern variable is introduced by a statement

In 6.3.1 it mentions Scope for Pattern Variables in Expressions under which it states when pattern variables are introduced for &&, ||, !, ?:, etc.

But I feel the explanation is very confusing, can anyone elaborate on &&, ||, !

Example of pattern variables-

Object o = "a";

if(o instanceof String s) {
    System.out.println(s); 
}

Where I am confused-

class foo {
    String s, n, p, m;

    void method() {
        Object o = "s";
        if (!(o instanceof Integer s) && o instanceof Integer n) {
            System.out.println(s + " " + n);  // n in scope but s is not in scope
        } else {
            System.out.println(s + " " + n); // neither s nor n is in scope
        }
        System.out.println(s + " " + n); // neither s nor n is in scope (Instance variables s and n over here)

        if (!(o instanceof String p) || o instanceof Integer m) {
            System.out.println(p + " " + m); // neither p nor m is in scope (Instance variables p and m over here)
        } else {
            System.out.println(p + " " + m); // p in scope but m is not in scope
        }

    }

}

I don't get how it resolute the scope of a variable at compile time. Also, why isn't s in the scope of else block and why is p in the scope of else block. I don't understand how pattern variable scoping works with a mix of &&,|| and !.


Please give simple as well as complicated examples. Please try to explain it with simple and difficult examples, would really be helpful.

Solution

  • Lets just consider this:

    if (!(o instanceof Integer s)) {
        System.out.println(s);
    

    It says:

    When o is an Integer bind it to s.

    Then if o is not an Integer, print s.

    Intuitively: when o is not an Integer, we didn't bind it to s, so s is meaningless.

    If you look at a more complicated example, it will most likely have this kind of logic at its root.

    The section of the JLS that specifies this is ... complicated. But I don't think you need to understand all of that complexity to use pattern variables. Just use the intuitive meaning behind these two sentences from the JLS 6.3:

    "The scope of a pattern variable declaration (that is, a local variable declared by a pattern) is the part of the program that might be executed after the matching of a value against the pattern has succeeded. It is determined by considering the program points where the pattern variable is definitely matched in a region beginning with the pattern that declares the pattern variable."

    So in our simple example, the System.out.println(s) is NOT part of the program that would be executed if (o instanceof Integer s) succeeded. The ! means that the then branch of this if is executed when (o instanceof Integer s) does not succeed.