• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • Liutauras Vilda
  • Jeanne Boyarsky
  • paul wheaton
Sheriffs:
  • Ron McLeod
  • Devaka Cooray
  • Henry Wong
Saloon Keepers:
  • Tim Holloway
  • Stephan van Hulst
  • Carey Brown
  • Tim Moores
  • Mikalai Zaikin
Bartenders:
  • Frits Walraven

instanceof code snippet compiles, when it shouldn't?

 
Ranch Hand
Posts: 39
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi all,
Apologies for the simple question, but why does this code compile? I thought the pattern variable on the right cannot be the same as the left  and must be a strict subtype, i.e. a subclass of Integer?

 
Marshal
Posts: 79929
396
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
There's nothing wrong with that code. The instanceof operator tests that its left operand is not null, and that it can safely be cast to the type on its right. A cast (Integer) value will obviously succeed, so that test will return true. You don't seem to be using data anywhere, but it is a fresh member of the alphabet of variables at that point.
A use of instanceof will only fail to compile if at compile time it is obvious that the test for casting will fail. You will find all the gory details in the JLS (=Java® Language Specification).
 
Tim Bant
Ranch Hand
Posts: 39
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Brilliant, thanks Campbell
 
Campbell Ritchie
Marshal
Posts: 79929
396
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Remember that you can cast anything to the type it already has. JLS section.
 
Campbell Ritchie
Marshal
Posts: 79929
396
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Bant wrote:. . . thanks Campbell

That's a pleasure
 
Tim Bant
Ranch Hand
Posts: 39
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
One more ... why is it that Set doesn't produce any output?



when I pass print (List.of(1,2)) ?
 
Saloon Keeper
Posts: 28313
207
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:You don't seem to be using data anywhere, but it is a fresh member of the alphabet of variables at that point.


This confused me. It was, I think, syntactically invalid in Java 6, but I skipped to the Java 21 JLS syntax specs and apparently instanceof changed to include a LocalVariableDefinition (Integer data) as an allowable RHS operand.

The compiler should probably have flagged "data" as an unused variable, though.
 
Saloon Keeper
Posts: 10924
87
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Bant wrote:One more ... why is it that Set doesn't produce any output?



when I pass print (List.of(1,2)) ?


A List cannot be cast to a Set.
 
Campbell Ritchie
Marshal
Posts: 79929
396
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Holloway wrote:. . . . It was . . . syntactically invalid in Java 6, but . . . the Java 21 . . . instanceof changed to include a LocalVariableDefinition (Integer data) as an allowable RHS operand.

Yes, that changed a long time ago, maybe even in Java9. I think it is called a pattern.

The compiler should probably have flagged "data" as an unused variable, though.

Why? Compilers don't usually make that sort of check.
 
Campbell Ritchie
Marshal
Posts: 79929
396
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Bant wrote:One more ... why is it that Set doesn't produce any output? . . .

But your code should still compile first time.
 
Tim Holloway
Saloon Keeper
Posts: 28313
207
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:

Tim Holloway wrote:. . . . It was . . . syntactically invalid in Java 6, but . . . the Java 21 . . . instanceof changed to include a LocalVariableDefinition (Integer data) as an allowable RHS operand.

Yes, that changed a long time ago, maybe even in Java9. I think it is called a pattern.


No, "Pattern" is the other option.

Campbell Ritchie wrote:

The compiler should probably have flagged "data" as an unused variable, though.

Why? Compilers don't usually make that sort of check.


Sure they do. All the time. I've even worked with C compilers whose lint-checking required a pragma to tell the compiler not to whine about it. It's a variant of the "statement has no effect" warning. In both cases, you'd want to know because at best it's lint, and at worst, you forgot something. Or haven't yet implemented something and it doesn't want you to forget.
 
Master Rancher
Posts: 5057
81
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Going back to the original question, that code compiles under Java 21, but not Java 17.  They changed the rules to be slightly more permissive as of Java 21.  This applies specifically to instanceof used for pattern matching, meaning the one with a new local variable name after the class name.  Previous JLS editions (through Java 20) contained the rule

If the type of the RelationalExpression is a subtype of the type of the Pattern, then a compile-time error occurs.


(Compare JLS 20 15.20.2 with JLS 21 15.20.2, under "The following rules apply when instanceof is the pattern match operator:", you can even see a few sloppily-edited blank lines where they deleted things but didn't fix the line afterwards.). The reason they made this change is because they were enhancing pattern matching rules to be used in switch statements as well as instanceof, and this change made things simpler for them.

[Credit to Paul Anilpram for pointing this out, back here.]

So, for Tim Bant: the "strict subtype" rule you learned is indeed valid for Java 17, but not Java 21.  

Tim Holloway wrote:

Campbell Ritchie wrote:

Tim Holloway wrote:. . . . It was . . . syntactically invalid in Java 6, but . . . the Java 21 . . . instanceof changed to include a LocalVariableDefinition (Integer data) as an allowable RHS operand.

Yes, that changed a long time ago, maybe even in Java9. I think it is called a pattern.


No, "Pattern" is the other option.


Allowing instanceof to have a local variable definition in the RHS is, indeed, called a pattern, and it happened in Java 16 (previewed in 14 and 15). JEP 394: Pattern Matching for instanceof

Tim Holloway wrote:

Campbell Ritchie wrote:

The compiler should probably have flagged "data" as an unused variable, though.

Why? Compilers don't usually make that sort of check.


Sure they do. All the time. I've even worked with C compilers whose lint-checking required a pragma to tell the compiler not to whine about it. It's a variant of the "statement has no effect" warning. In both cases, you'd want to know because at best it's lint, and at worst, you forgot something. Or haven't yet implemented something and it doesn't want you to forget.


Compilers in general certainly can issue warnings for unused variables.  I don't think I've even seen the javac compiler do it, though.  I get warnings from IntelliJ, and I'm sure other IDEs and lint tools do it, but not javac, as far as I know.  Not sure why not.  I know they can't legally (per JLS) error out on such code, but a warning would certainly be allowed.  They just don't actually do it.
 
Mike Simmons
Master Rancher
Posts: 5057
81
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Bant wrote:I thought the pattern variable on the right cannot be the same as the left  and must be a strict subtype, i.e. a subclass of Integer?


[...]

Mike Simmons wrote:So, for Tim Bant: the "strict subtype" rule you learned is indeed valid for Java 17, but not Java 21.


Sorry, this was wrong.  There is no strict subtype rule.  For example:

Here Foo and Bar could be two unrelated interfaces.  The compiler has no way of knowing in advance whether getFoo() will return a Foo that is also a Bar, or not.  So it's not going to disallow you from checking that with instanceof.  The compiler will check that the two types are compatible, meaning it will error out if there is no possible way the instanceof could ever be valid.  But that's different than requiring a "strict subtype".

You were right to think that the pattern variable on the right cannot be the same as the left, prior to Java 21.  But it doesn't have to be a strict subtype - it could also be unrelated.

If you read this rule back in the OCP 17 book, in our previous thread author Jeanne Boyarsky observed that the rule was given in a chapter before interfaces had been explained, and they were trying to keep things simple.  And it's true, if interfaces did not exist, then the type of the pattern variable on the right would have to be a subtype (strict subtype, prior to Java 21) of the reference type.  But since interfaces do exist, that rule is not correct, as initially stated.  Apparently a later chapter may correct this, after they teach interfaces.
 
Tim Holloway
Saloon Keeper
Posts: 28313
207
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Mike Simmons wrote:
Allowing instanceof to have a local variable definition in the RHS is, indeed, called a pattern, and it happened in Java 16 (previewed in 14 and 15). JEP 394: Pattern Matching for instanceof


Not in this case. Note the capitalizations I used for my terms. They come straight from the Java 21 JLS. This is a LocalVariableDefinition, not a Pattern. Those are the two options for RHS expressions on Java 21's instanceof operation.

I wouldn't say the rules have been "relaxed", but rather altered to permit enhanced functionality.

I actually don't know why one would choose to define a variable in an instanceof expression, but as of Java 12, it's syntactically valid. Presumably that meant it was important to someone.
 
Mike Simmons
Master Rancher
Posts: 5057
81
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Holloway wrote:

Mike Simmons wrote:
Allowing instanceof to have a local variable definition in the RHS is, indeed, called a pattern, and it happened in Java 16 (previewed in 14 and 15). JEP 394: Pattern Matching for instanceof


Not in this case. Note the capitalizations I used for my terms. They come straight from the Java 21 JLS. This is a LocalVariableDefinition, not a Pattern. Those are the two options for RHS expressions on Java 21's instanceof operation.


Hmm, I don't see where you're getting that.  The two options I see under LocalVariableDefinition are ReferenceType and Pattern.  Pattern then splits into TypePattern and RecordPattern, and TypePattern is (syntactically) equivalent to LocalVariableDeclaration.  That is, LocalVariableDefinition is found among the options under Pattern, not ReferenceType.

Here are the relevant definitions I found, excerpted from Chapter 19: Syntax, also found spread throughout the other chapters; InstanceofExpression is found in 15.20.2 which I liked to previously.

Is there another pathway where LocalVariableDeclaration is found under InstanceofExpression but not under Pattern?  I don't think so - but it can be easy to get turned around in these definitions; I won't rule it out.
 

Tim Holloway wrote:I wouldn't say the rules have been "relaxed", but rather altered to permit enhanced functionality.


Six of one, a half dozen of the other, I think.  The specific rule I was talking about, "If the type of the RelationalExpression is a subtype of the type of the Pattern, then a compile-time error occurs" has been removed entirely; that part seems like a relaxation of the rules.  As I said, they did this to allow for patterns in switch statements, which I agree is allowing enhanced functionality.

Tim Holloway wrote:I actually don't know why one would choose to define a variable in an instanceof expression, but as of Java 12, it's syntactically valid. Presumably that meant it was important to someone.


Mostly it allows you to skip the need to then cast the reference after an instanceof - instead, you use the new name to reference the newly-refined type.  So you can replace

with

Not a big deal when the name is as short as "Bar", but it's more appreciable when you're dealing with those ReallyFreakingHugeClassNamesThatAreSoUbiquitousInMostJavaShops.  It's just some low-grade syntactic sugar that they picked up while working on their main objective, pattern matching in switch.

 
Tim Holloway
Saloon Keeper
Posts: 28313
207
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, now, I'm confused. I thought I pulled that from JLS 21, but the syntax diagram I was using said specifically "LocalVariableDefinition", not ReferenceType. Looking for the proper version of Java documentation via Google has always been a hazardous endeavor.

Campbell's example makes sense as it is a scope-limited conditional, analogous to try-with-resources. It's syntactic shorthand rather than essential, but I can see its virtue now.
 
Campbell Ritchie
Marshal
Posts: 79929
396
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Holloway wrote:. . . I actually don't know why one would choose to define a variable in an instanceof expression . . .

I can think of few places where instanceof actually constitutes good programming, but here is one such.
Old way to do it, which will fall over if text == null:-New way to do it:-See, goodbye nasty awkward casts

[edit]Did you notice the spelling error in my code, which will cause it to fail to compile? I can't be bothered to correct it.
 
Campbell Ritchie
Marshal
Posts: 79929
396
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You will find the syntax elsewhere in the JLS: here. I am pretty sure the ch 19 link Mike gave gives you the same syntax.
 
Tim Holloway
Saloon Keeper
Posts: 28313
207
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Oh, yeah!  
 
To do a great right, do a little wrong - shakepeare. twisted little ad:
Gift giving made easy with the permaculture playing cards
https://coderanch.com/t/777758/Gift-giving-easy-permaculture-playing
reply
    Bookmark Topic Watch Topic
  • New Topic