Sunday, February 28, 2021

Scoping of binding variables

Binding variables of instanceof operator is visible only inside of the code blocks that are reachable when the instanceof operator evaluates to true. 

Below sample illustrates this.


interface Pet {
    default public String color() {
        return this.color();
    }

}

record Dog(String color) implements Pet {

    public void bark() {
        System.out.println("I bark...");
    }
}

record Cat(String color) implements Pet {

    public void meaw() {
        System.out.println("I meaw...");
    }
}

public class Main {

    public static void main(String[] args) {

        Pet p1 = new Dog("White");
        Pet p2 = new Cat("White");

        if (p1 instanceof Dog d) {
            d.bark();
        }

        if (p2 instanceof Cat c) {
            c.meaw();
        }

        d.bark(); 
        c.meaw(); // Will not compile. c & d are not visible beyond their respective if blocks
    }
}

In the above sample, lines c.meaw()  and d.bark() outside of the if statement will not compile, as at this point c & d are not visible. 

Now we will make a few changes to the above code to study the scope of binding variables in-depth. 

First lets try to move the instanceof operator with binding variable outside of the if block. The main method is changed as shown below

    public static void main(String[] args) {

        Pet p1 = new Dog("White");
        Pet p2 = new Cat("White");

        boolean isDog = p1 instanceof Dog d;
        boolean isCat = p2 instanceof Cat c;

        d.bark();
        c.meaw();

    }

In the code above, it looks like c & d should be visible through the rest of the main() method. But this code also fails to compile. Binding variables c & d are not visible beyond the line containing their respective instanceof operator 

The code block that is reachable, when the instanceof operator evaluates to true is empty and its scope ends with assigning its result to the boolean variable. The code lines d.bark() and c.meaw() gets executed irrespective of if the instance of operator evaluates to true of false 

This explains why the binding variables are not visible beyond their respective instanceof operator statements. Easy!!! Below scenario gets a bit more tricky

Now lets modify the code to use both the instanceof binding inside of an if block, combining the two instance of operator with a logical & operator as shown below

    public static void main(String[] args) {

        Pet p1 = new Dog("White");
        Pet p2 = new Cat("White");

        if (p1 instanceof Dog d & p2 instanceof Cat c) {
            d.bark();
            c.meaw();
        }
    }

Phew... the code still doesn't compile. Binding variables c and d are not visible inside of the if block :(

Since the logical AND (&) operator is not short-circuiting and the second condition gets executed even which the first check evaluates to false, the scope of the binding variable is not extended beyond the instanceof operator statement and hence not visible inside of the if block!!! Bit tricky, but thats how the scope of the binding variable is...

And now, lets try with the short circuit AND operator (&&) as shown below

    public static void main(String[] args) {

        Pet p1 = new Dog("White");
        Pet p2 = new Cat("White");

        if (p1 instanceof Dog d && p2 instanceof Cat c) {
            d.bark();
            c.meaw();
        }
    }

This time, code compiles and executes as expected. Every piece of code beyond the instanceof binding variable assignment gets executed if and only if the instance of operator evaluates to true. This makes the binding variables c and d visible inside of the if block. 

And there is another interesting case on the scope of binding variable when used with the NOT (!) operator. We will explore that in the next post.


Sample code used in this post can be downloaded from https://github.com/ashokkumarta/awesomely-java/tree/main/2021/02/Language-Features/Instanceof-Binding-Variable/Scoping

No comments:

Post a Comment