What is the difference between the 'instanceof' and 'in' keywords? - groovy

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

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.

Related

How to know if object is a singleton in Kotlin?

I would like to define toString()in superclass so, that it detects that class instance is a singleton (an object) and print its name.
Is it possible in Kotlin?
The following objectInstance property of KClass can be helpful:
/**
* The instance of the object declaration, or `null` if this class is not an object declaration.
*/
public val objectInstance: T?
Here's an example:
object Singleton
println(Singleton::class.objectInstance) // xx.Singleton#77a57272
println(""::class.objectInstance) //null

Groovy coercing List to Map doesn't throw ClassCastException or what is ArrayList1_groovyProxy?

I was writing code where I tried to cast an Object to a Map.
Map a = object as Map
I could alternatively use
Map a = (Map) object
and the whole question would be irrelevant as this throws a ClassCastException if the object is of type List, but by using the former I encountered an interesting thing.
If the object is a List, i.e. object = [], groovy type coercion will behave different from what I expected.
My expectation was to get a ClassCastException, but instead I got a resulting object. But this object seems odd. It is an instance of List and an instance of Map and using .toString() on it resulted in the output of a List, not a Map ([a,b]). Also it is not possible to set a value on the map with a['c'] = 'c'. This results in a java.lang.IllegalArgumentException: argument type mismatch.
Map a = ['a', 'b'] as Map
println(a)
println(a instanceof List)
println(a instanceof Map)
println(a.getClass())
results in the following output:
[a, b]
true
true
class ArrayList1_groovyProxy
I tried to google to find out what this ArrayList1_groovyProxy is, but couldn't find anything.
It still doesn't make sense to me, that the coercion returns an object that obviously is not really what it should be and also seems kind of broken, instead of just throwing a ClassCastException.
Can anyone explain to me the reasoning behind that behavior instead of throwing the exception and explain the use of ArrayList1_groovyProxy? Or is this just a bug in groovy?
The as operator calls the asType method with the provided type as the argument to the method.
You can see the default implementation for asType in DefaultGroovyMethods.
Since Map is an interface, it will eventually call ProxyGenerator.INSTANCE.instantiateDelegate(interfaces, obj), which returns a dynamic proxy that implements Map.
/**
* Converts a given object to a type. This method is used through
* the "as" operator and is overloadable as any other operator.
*
* #param obj the object to convert
* #param type the goal type
* #return the resulting object
* #since 1.0
*/
#SuppressWarnings("unchecked")
public static <T> T asType(Object obj, Class<T> type) {
if (String.class == type) {
return (T) InvokerHelper.toString(obj);
}
// fall back to cast
try {
return (T) DefaultTypeTransformation.castToType(obj, type);
}
catch (GroovyCastException e) {
MetaClass mc = InvokerHelper.getMetaClass(obj);
if (mc instanceof ExpandoMetaClass) {
ExpandoMetaClass emc = (ExpandoMetaClass) mc;
Object mixedIn = emc.castToMixedType(obj, type);
if (mixedIn != null)
return (T) mixedIn;
}
if (type.isInterface()) {
try {
List<Class> interfaces = new ArrayList<Class>();
interfaces.add(type);
return (T) ProxyGenerator.INSTANCE.instantiateDelegate(interfaces, obj);
} catch (GroovyRuntimeException cause) {
// ignore
}
}
throw e;
}
As to why Groovy goes to such great lengths to coerce types--it's basically the nature of Groovy: making Java coding easier. You can construct an object by passing a Map to its constructor, or even coerce a Map instance to a particular type; so why not let every object be coerced back into a Map via the as operator?

Overload == in Groovy to not return boolean

I'm currently developing a DSL using Groovy for a math related API written in Java.
The Expression class has a method with the following signature:
public Constraint equals(Expression that)
We want to define a constraint, which will only be evaluated later.
Is it possible to override == using our equals implementation so that it doesn't return boolean but Constraint?
No, as far as I know, it is not possible...
The == operator at some point ends up in DefaultTypeTransformation.java::compareEqual which returns boolean, so even if you do:
class Yay {}
class Woo {
String equals(Yay y) {
'hello'
}
}
println new Woo() == new Yay()
You will get the exception:
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Boolean
at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.compareEqual(DefaultTypeTransformation.java:641)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareEqual(ScriptBytecodeAdapter.java:684)
at ConsoleScript3.run(ConsoleScript3:9)
It will work with a.equals(b), but not a == b

Groovy adding code to a constructor

Is there a way in Groovy that I can add code to a constructor when a class is instantiated? I have a Groovy class (but I can't modify the source of this particular one), but I was hoping there was a way to inject code (maybe via the metaclass) so my code gets run as part of the constructor (in this case there is only one, default constructor).
Thanks,
Jeff
You can override the constructor, but it's a little tricky, particularly if you're overriding the default constructor. You need to assign a closure to the class's metaClass.constructor, and the closure should return a new instance. The tricky part is that if you call the constructor you've overriden, you'll get into a recursive loop and generate a stack overflow. You need another way to get an instance of the class, such as a different constructor.
For testing, it's sometimes possible to get around this limitation. Usually, it's enough to first instantiate an object, then override the constructor to return the existing instance. Example:
class MyObject {
String something
MyObject() { something = "initialized" }
}
testInstance = new MyObject()
testInstance.something = "overriden"
MyObject.metaClass.constructor = { -> testInstance }
aNewObject = new MyObject()
assert aNewObject.is(testInstance)
assert aNewObject.something == "overriden"
It is possible to add new constructors or replace the old one. If you need the original constructor, you can use reflection for that:
MyObject.metaClass.constructor = { -> // for the no-arg ctor
// use reflection to get the original constructor
def constructor = MyObject.class.getConstructor()
// create the new instance
def instance = constructor.newInstance()
// ... do some further stuff with the instance ...
println "Created ${instance}"
instance
}
Note that you have to change this if you have parameters to your constructors, e.g:
// Note that the closure contains the signature of the constructor
MyObject.metaClass.constructor = { int year, String reason ->
def constructor = MyObject.class.getConstructor(Integer.TYPE, String.class)
def instance = constructor.newInstance(
2014, "Boy, am I really answering a question three years old?")
// ... do some further stuff with the instance ...
println "Created ${instance}"
instance
}
PS: Note that when you want to add constructors which are not yet existent, use the << operator instead: MyObject.metaClass.constructor << { /* as above */ }.
You can bypass the limitations in the solution proposed by storing the original constructor using standard Java reflection. For example, this is what I do initialize a class (basic injection) in a spock test:
def setupSpec() {
MockPlexusContainer mockPlexusContainer = new MockPlexusContainer()
def oldConstructor = MY_CLASS.constructors[0]
MY_CLASS.metaClass.constructor = { ->
def mojo = oldConstructor.newInstance()
mockPlexusContainer.initializeContext(mojo)
return mojo
}
}
This gets invoked only once, but eveytime someone calls a constructor I get a different instance avoiding cleaning values and ensuring thread safety.

c# Generics new() constraints with type: (new(T))

I'm building a little helper to turn EF4 objects to POCOs.
(I know there is AutoMapper, but I'm having a c# dilemma at this time)
How can I make this work (the where P: new(E) is not legal
I wish to make sure the P (POCO) class as a constructor that takes the E class
(hence handling the transformation)
How can I make this work ?
How can I make a generic function in C# that can take a new(type) constraint ?
public static List<P> ListConvert<E, P>(List<E> efList) where P: new(E)
{
List<P> pList = new List<P>();
foreach (E item in efList)
{
P myItem = new P(item);
pList.Add(myItem);
}
return pList;
There's no such constraint. What you can do is have an extra parameter:
public static List<P> ListConvert<E, P>(List<E> efList, Func<E, P> func)
That way it isn't required to be a constructor, but you can pass in a delegate which calls the constructor:
ListConvert(list, x => new Foo(x))
I have a blue-sky idea which would enable constructor constraints, called "static interfaces" - these would only be useful for generic constraints, but would also enable some operator use cases.
This is not possible. The new constraint only allows you to create objects via a public parameterless constructor.
There's no such thing as P : new(E), but you could have the caller supply a delegate that knows how to construct a P given an E:
public static List<P> ListConvert<E, P>(List<E> efList, Func<E, P> converter)
{
List<P> pList = new List<P>();
foreach (E item in efList)
{
P myItem = converter(item);
pList.Add(myItem);
}
return pList;
}
However, if you're doing this, you may as well use LINQ: efList.Select(e => new P(e)).ToList().

Resources