3

I am using the example from Java the complete reference by Herbert Schildt, 12th ed and Java is 14

Where he gives the 2 following examples (if blocks), the first one is ok and the 2nd one is wrong therefore commented

public class PatternMatch {
    public static void main(String[] args){
        Number myOb = Integer.valueOf(9);
        int count = 10;
        if((count < 100) && myOb instanceof Integer iObj) { // is OK!!!
            iObj = count;
        }

        /*
        if((count < 100) & myOb instanceof Integer iObj) { // Error!!!
            iObj = count;
        }
        */
    }
}

His explanation on why the 2nd if block (commented out) is "In this case, the compiler cannot know whether or not iObj will be in scope in the if block because the right side of the & will not necessarily be evaluated". This leads to my confusion: & makes sure both its left and right sides are ALWAYS evaluated so why "because the right side of the & will not necessarily be evaluated"?

Thanks!

if you put the java14 code in your IDE, you do see the 2nd if block produces the compilation error saying iObj not defined... but I just don't understand his explanation:

His explanation on why the 2nd if block is "In this case, the compiler cannot know whether or not iObj will be in scope in the if block because the right side of the & will not necessarily be evaluated". This leads to my confusion: & makes sure both its left and right sides are ALWAYS evaluated so why "because the right side of the & will not necessarily be evaluated"?

public class PatternMatch {
    public static void main(String[] args){
        Number myOb = Integer.valueOf(9);
        int count = 10;
        if((count < 100) && myOb instanceof Integer iObj) { // is OK!!!
            iObj = count;
        }

    
        if((count < 100) & myOb instanceof Integer iObj) { // Error!!!
            iObj = count;
        }
   
    }
}
  • 2
    Java 14 is end-of-life. You shouldn't be using it to learn about new Java language constructs. Use Java 17. (Or later if you are trying to learn about post Java 17 features ...) I don't know if it will make a difference here ... but this could be a Java compiler or JLS bug that has been fixed by Java 17. – Stephen C Mar 09 '23 at 00:35
  • 1
    @StephenC This has not changed since Java 14. – HTNW Mar 09 '23 at 00:39
  • 1
    Even so, using an EOL'd Java version to learn Java is ... asking for trouble. – Stephen C Mar 09 '23 at 00:40
  • Does this answer your question? [Why '&&' and not '&'?](https://stackoverflow.com/questions/7331686/why-and-not) – H3AR7B3A7 Mar 09 '23 at 00:43
  • my bad what i meant was really java 17 – davidandcode Mar 09 '23 at 01:19

1 Answers1

3

Indeed, 'right side will not necessarily be evaluated' is just completely wrong.

&& is legal because within the if statement, you have an absolute guarantee that myObj instanceof Integer iObj will have been evaluated, and evaluated to true (thus establishing iObj in the scope of the code inside the if block). Given a && b, b is not neccessarily evaluated, but if code flows into that if, b definitely has been, which is why your first snippet compiles.

& is presumably not legal here because the spec didn't bother. There is no explanation that involves a scenario where myObj instanceof Integer iObj either didn't get evaluated, or evaluated to false somehow. Inside the if block, it will have been evaluated, and will have evaluated to true. But, the point is, the compiler has to figure out that based on static code analysis and that part is where the spec doesn't bother listing out explicitly that boolean & boolean establishes definite evaluation (and definitely true evaluation).

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
  • in the & case, if the compiler can't figure out from static code if the "myObj instanceof Integer iObj" has been evaluated then why the compiler can figure it out in the && case? – davidandcode Mar 09 '23 at 01:39
  • 1
    Because the spec says that the compiler must do so for `&&`, and not for `&`. As I said, 'cuz spec said so' is what this boils down to. There is no clear reason for why the spec says so. `javac` is on rails: It must do precisely what the spec says. No less, but also _no more_ either. – rzwitserloot Mar 09 '23 at 04:26
  • 2
    @H3AR7B3A7 the `&` operator is as old as the `&&` operator—both exist in Java since day one. And it’s not helpful to call `&` a “bitwise operator”, as you can use it for `boolean` expressions too. And in case of the “Definite Assignment” rules, it is considered. It’s just that there is no point in ever appending `& … instanceof …` to a condition, as that would mean: “perform this type check even if you know that it has no effect” – Holger Mar 09 '23 at 11:41
  • @Holger is playing a dangerous game, trying to divine the intent of the spec author, but '... this seems kinda useless' is a very plausible guess. Various OpenJDK team leads and committers are on record about wanting to err on the side of disallowing things rather than allowing them, because you can 'fix' a disallow into an allow later with more insights, but you can't change an allow into a disallow later with more insight (not without breaking backwards compatibility). "Seems useless" + "when in doubt, disallow" together are hopefully enough to satisfy your curiosity :) – rzwitserloot Mar 09 '23 at 12:54
  • And that record is the various mailing lists, such as [amber-dev](https://mail.openjdk.org/mailman/listinfo/amber-dev), core-libs-dev, valhalla-dev, etcetera. – rzwitserloot Mar 09 '23 at 12:55
  • 1
    I did not intent to pretend to know the spec author’s intention. My comment was meant as a response to a now-deleted comment, addressing the actual differences between `&` and `&&`. You’re right that it is an established practice to start with disallowing something (or everything except something) and waiting whether someone requests adding the missing feature. Well, and that leads to the conclusion that it is rather unlikely that someone can explain why they need support for writing `& … instanceof …` instead of `&& … instanceof …`… – Holger Mar 09 '23 at 13:05
  • Is there any way that I can see how & and && were compiled? – davidandcode Mar 09 '23 at 19:30
  • Sure, `javap -c -v ClassName` can do that. – rzwitserloot Mar 10 '23 at 01:06