3

For the purposes of verifying class membership, the in and instanceof keywords appear to behave identically. So what's the difference between the two? Is there even a difference at all? There are several questions on StackOverflow (here or here) where both keywords are given as solutions for this purpose, but there is no mention on the difference between the two or when it is more appropriate to use one over the other. Additionally, the official documention mentions that the in keyword is equivalent to calling an object's isCase() method, but doesn't detail what the instanceof keyword does.


Both keywords appear to behave identically with respect to class inheritance and interface implementation:

class MyMap extends LinkedHashMap { }

def foo = new LinkedHashMap()
def bar = new MyMap()

println("LinkedHashMap instance is 'in' LinkedHashMap: ${foo in LinkedHashMap}")
println("LinkedHashMap instance is 'instanceof' LinkedHashMap: ${foo instanceof LinkedHashMap}")
println("LinkedHashMap instance is 'in' Map: ${foo in Map}")
println("LinkedHashMap instance is 'instanceof' Map: ${foo instanceof Map}")
println("MyMap instance is 'in' LinkedHashMap: ${bar in LinkedHashMap}")
println("MyMap instance is 'instanceof' LinkedHashMap: ${bar instanceof LinkedHashMap}")
println("MyMap instance is 'in' Map: ${bar in Map}")
println("MyMap instance is 'instanceof' Map: ${bar instanceof Map}")

Output:

LinkedHashMap instance is 'in' LinkedHashMap: true
LinkedHashMap instance is 'instanceof' LinkedHashMap: true
LinkedHashMap instance is 'in' Map: true
LinkedHashMap instance is 'instanceof' Map: true
MyMap instance is 'in' LinkedHashMap: true
MyMap instance is 'instanceof' LinkedHashMap: true
MyMap instance is 'in' Map: true
MyMap instance is 'instanceof' Map: true
jayhendren
  • 4,286
  • 2
  • 35
  • 59

1 Answers1

6

The main difference is that instanceof is a Java keyword, while obj in SomeClass is an equivalent of SomeClass.isCase(obj) method call as you mentioned in your question.

There is one major implication: instanceof cannot be overridden and as Oracle docs says:

The instanceof operator compares an object to a specified type. You can use it to test if an object is an instance of a class, an instance of a subclass, or an instance of a class that implements a particular interface.


Source: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op2.html

Class.isCase(obj) is implemented as follows:

/**
 * Special 'Case' implementation for Class, which allows testing
 * for a certain class in a switch statement.
 * For example:
 * <pre>switch( obj ) {
 *   case List :
 *     // obj is a list
 *     break;
 *   case Set :
 *     // etc
 * }</pre>
 *
 * @param caseValue   the case value
 * @param switchValue the switch value
 * @return true if the switchValue is deemed to be assignable from the given class
 * @since 1.0
 */
public static boolean isCase(Class caseValue, Object switchValue) {
    if (switchValue instanceof Class) {
        Class val = (Class) switchValue;
        return caseValue.isAssignableFrom(val);
    }
    return caseValue.isInstance(switchValue);
}

Source: org/codehaus/groovy/runtime/DefaultGroovyMethods.java#L1121

As you can see based on the source code Groovy's obj in SomeClass is not an alias to instanceof, because it does a bit more. However, there is one important thing worth mentioning - you can override isCase() implementation, but you can't change how instanceof Java keyword behaves. Overriding Class.isCase() may cause some damage to your code if you use it as an alternative to Java's instanceof keyword.

Szymon Stepniak
  • 40,216
  • 10
  • 104
  • 131
  • Wow, very thorough answer with sources. Thanks! I'm also curious if there are any cases where `someObject instanceof SomeClass` would have different behavior than `someObject in SomeClass` (barring overriding `isCase()`). Based on the information given, it would seem that, for all practical purposes, the two behave the same, even if they are not strictly equivalent. – jayhendren Oct 31 '18 at 20:21
  • Found one difference: `Object in Class` -> false. `Object instanceof Class` -> true. – jayhendren Oct 31 '18 at 20:33