Bug? "Reference to method is ambiguous" in Groovy - groovy

package bug
import groovy.transform.CompileStatic
#CompileStatic
class BugCheck
{
static void main(String[] args)
{
new BugCheck()
}
BugCheck()
{
new Child().method(1f) // causes the problem
}
class Parent
{
void method(float f, boolean b=true)
{
println("Parent")
}
}
class Child extends Parent
{
#Override
void method(float f)
{
println("Child")
}
}
}
Compiling this piece of code with Groovy 2.3.4 leads to the following error:
/mirror/dev/Groovy/src/bug/BugCheck.groovy: 17: [Static type checking] - Reference to method is ambiguous. Cannot choose between [void bug.BugCheck$Child#method(float), void bug.BugCheck$Child#method(float)]
Is this a bug in Groovy, or do I miss something here?

The method signatures vary, but since the Parent method has a default value, calling it with no boolean value creates an ambiguity: do you mean the Child method with no parameter, or the parent with a default boolean?
If Child declares a method with the exact same signature the ambiguity is resolved.
From a language design (or usage?) standpoint this is pretty shaky reasoning, though; IMO the Child method should be called if no boolean is provided. IMO the confusion is warranted.

Related

Why does accessing local variables during anonymous class construction cause NPE

Given a relatively simple class
class TestNull {
static void main(String [] a) {
Long whatever = 1
// this works
new Runnable() {
void run() { println(whatever) }
}.run()
// this doesn't
new Weird() {
#Override
void x() { println(whatever) } // NPE
}
}
static abstract class Weird {
Weird() { x() }
abstract void x();
}
}
executing main() throws an NPE trying to access whatever during the construction of anonymous class extending Weird. The same code works fine in Java, and it also works fine as long as the variable is accessed after the class is constructed (hence the example with anonymous Runnable).
I wonder what's going on here, whether this is a Groovy bug (I'm testing with 3.0.5), or it's supposed to be like that. But then I'm not sure what exactly is null in this case, and how do you even logically explain what the rule is for accessing external scope variables from anonymous classes...
NPE:
Exception in thread "main" java.lang.NullPointerException
at org.example.TestNull$2.x(TestNull.groovy:15)
at org.example.TestNull$Weird.<init>(TestNull.groovy:20)
at org.example.TestNull$2.<init>(TestNull.groovy)
at org.example.TestNull.main(TestNull.groovy:13)

How to reference subclass from a static superclass method in Groovy

A simplified version of what I'm trying to do in Groovy:
class Animal {
static def echo() {
println this.name // ie "class.name"
}
}
class Dog extends Animal {
}
class Cat extends Animal {
}
Dog.echo()
Cat.echo()
// Output:
// => Animal
// => Animal
//
// What I want:
// => Dog
// => Cat
I think what I'm asking here is: when I call a static method on an object, and
the static method is defined in the object's superclass, is there a way to obtain
the actual type of the object?
A static method is not defined in the object context, but in the class context. You might get confused by the presence of this in the Groovy static method. However, it's only a syntactic sugar that eventually replaces this.name with Animal.class.name.
If you compile the Animal class from your example with a static compilation enabled, you will see that it compiles to the following Java equivalent (result after decompiling the .class file):
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
public class Animal implements GroovyObject {
public Animal() {
MetaClass var1 = this.$getStaticMetaClass();
this.metaClass = var1;
}
public static Object echo() {
DefaultGroovyMethods.println(Animal.class, Animal.class.getName());
return null;
}
}
You can see that the following line in the echo method:
DefaultGroovyMethods.println(Animal.class, Animal.class.getName());
operates directly on the Animal class name. So from the echo method perspective, it doesn't matter how many classes extend it. As long as those classes invoke echo method defined in the Animal class, you will always see Animal printed as a result.
And there is even more than that. If you use the following compiler configuration script:
config.groovy
withConfig(configuration) {
ast(groovy.transform.CompileStatic)
ast(groovy.transform.TypeChecked)
}
and then compile the script (let's call it script.groovy) using this configuration option with the following command:
groovyc --configscript=config.groovy script.groovy
then you will see something like this after decompiling the .class file:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import groovy.lang.Binding;
import org.codehaus.groovy.runtime.InvokerHelper;
public class script extends groovy.lang.Script {
public script() {
}
public script(Binding context) {
super(context);
}
public static void main(String... args) {
InvokerHelper.runScript(script.class, args);
}
public Object run() {
Animal.echo();
return Animal.echo();
}
}
You can see that even though you have invoked Dog.echo() and Cat.echo() in your Groovy script, the compiler replaced these calls with the double Animal.echo() invocation. It happened because calling this static method on any other subclass does not make any difference.
Possible solution: applying double dispatch
There is one way to get the expected output - override echo static method in Dog and Cat class. I can assume that your real method may do something more than the exemplary echo method you have shown above, so you might need to call the super echo method from a parent class. But... there are two problems: (1) you can't use super.echo() in the static context, and (2) it doesn't solve the problem, because parent method still operates in the Animal class context.'
To solve this kind of issue you might want to mimic a technique called double dispatch. In short - when we don't have information about the caller in the method that was called, let's allow the caller to pass this information with the method call. Consider the following example:
import groovy.transform.CompileStatic
#CompileStatic
class Animal {
// This is a replacement for the previous echo() method - this one knows the animal type from a parameter
protected static void echo(Class<? extends Animal> clazz) {
println clazz.name
}
static void echo() {
echo(Animal)
}
}
#CompileStatic
class Dog extends Animal {
static void echo() {
echo(Dog)
}
}
#CompileStatic
class Cat extends Animal {
static void echo() {
echo(Cat)
}
}
Animal.echo()
Dog.echo()
Cat.echo()
This may sound like a boilerplate solution - it requires implementing echo method in each subclass. However, it encapsulates the echo logic in the method that requires Class<? extends Animal> parameter, so we can let every subclass to introduce their concrete subtype. Of course, this is not a perfect solution. It requires implementing echo method in each subclass, but there is no other alternative way. Another problem is that it doesn't stop you from calling Dog.echo(Animal) which will cause the same effect as calling Animal.echo(). This double dispatch like approach is more like introducing a shorthand version of echo method which uses the common static echo method implementation for simplicity.
I don't know if this kind of approach solves your problem, but maybe it will help you find a final solution.

Closure Coercion not working in certain case

I'm calling a Java method from Groovy which expects an instance of a SAM interface as a parameter.
Normally Groovy is happy with passing in a closure in these cases, and will coerce it accordingly HOWEVER in this case, the interface extends another one and overrides the single method.
Note - It still only has one method, but it's been overriden.
In this instance Groovy doesn't automatically coerce the closure and the only way I seem to be able to call it is by using "AS".
I'm publishing an API to help kids to learn code and really don't want them to have to use "AS" because it would complicate things.
Here's some code that shows the issue...
Java
public interface BaseHandler<T> {
public void handle(T test);
}
public interface Handler extends BaseHandler<String> {
public void handle(String test);
}
public class LibraryClass {
public void method(Handler handler) {
handler.handle("WORLD!");
}
}
Groovy
LibraryClass bar = new LibraryClass();
bar.method({ name -> println "HELLO " + name})
Error
Caught: groovy.lang.MissingMethodException: No signature of method: Bar.doIt() is applicable for argument types: (testClosures$_run_closure1) values: [testClosures$_run_closure1#fe63b60]
Any help on how to get around this without using "AS" would be hugely appreciated
Groovy wants to implement the interface by coercion, but doesn't know which interface method it should implement. As there are 2:
the handle(String test) and a second one: handle(String test) (of the baseHandler)
The solution is to remove the handle(String test) from the handler (it adds nothing as the BaseHandler posesses this method already thanks to the generics).
Like this it works correctly:
public interface BaseHandler<T> {
public void handle(T test);
}
public interface Handler extends BaseHandler<String> {
}
public class LibraryClass {
public void method(Handler handler) {
handler.handle("WORLD!");
}
}

How does Groovy select method when a user-defined method conflicts with a GDK method

I wrote the following Java classes:
package com.example;
class MySet extends java.util.AbstractSet {
#Override public java.util.Iterator iterator() { return null; }
#Override public int size() { return 0; }
}
interface ToSet { MySet toSet(); }
public class MyList extends java.util.AbstractList implements ToSet {
#Override public Object get(int index) { return null; }
#Override public int size() { return 0; }
public MySet toSet() {
return new MySet();
}
}
and a test in Groovy:
package com.example
class MyTest {
#org.junit.Test
public void test() {
MySet set = new MyList().toSet();
println(set.class);
println(new MyList().toSet().class);
def set2 = new MyList().toSet();
println(set2.class);
}
}
The test run results in:
class com.example.MySet
class java.util.HashSet
class java.util.HashSet
My guess is that in the latter two cases the expression toSet() invokes the GDK's toSet method instead of MyList#toSet, but what is the exact rule about this behavior? Does Groovy's method selection depend not only on receiver and arguments, but also on the context?
One more subtle thing is that if I remove implements ToSet from the Java code above, the test prints class com.example.MySet for all three cases. So I got confused.
In the three examples you mention, your toSet method is never invoked. This is easily verified by adding a print statement to your toSet method in MyList. The reason the first class is printed as MySet is because of the assignment to a variable of the type MySet - Groovy will implicitly cast the HashSet to MySet upon assignment (magic!).
The rest of the behavior is more subtle. When no interface implementation is declared (you remove implements ToSet), Groovy method dispatcher will pick the method implementation on the MyList class, i.e. the method you defined. Apparently, when the interface implementation is defined, the method dispatcher has to choose between the interface implementation (MyList toSet) and the superclass implementation (GDK toSet), and it's choosing the latter (they both have no arguments).

groovy: variable scope in closures in the super class (MissingPropertyException)

I have the impression that closures run as the actual class being called (instead of the implementing super class) and thus break when some variables are not visible (e.g. private in the super class).
For example
package comp.ds.GenericTest2
import groovy.transform.CompileStatic
#CompileStatic
class ClosureScopeC {
private List<String> list = new ArrayList<String>()
private int accessThisPrivateVariable = 0;
void add(String a) {
list.add(a)
println("before ${accessThisPrivateVariable} ${this.class.name}")
// do something with a closure
list.each {String it ->
if (it == a) {
// accessThisPrivateVariable belongs to ClosureScopeC
accessThisPrivateVariable++
}
}
println("after ${accessThisPrivateVariable}")
}
}
// this works fine
a = new ClosureScopeC()
a.add("abc")
a.add("abc")
// child class
class ClosureScopeD extends ClosureScopeC {
void doSomething(String obj) {
this.add(obj)
}
}
b = new ClosureScopeD()
// THIS THROWS groovy.lang.MissingPropertyException: No such property: accessThisPrivateVariable for class: comp.ds.GenericTest2.ClosureScopeD
b.doSomething("abc")
The last line throws a MissingPropertyException: the child class calls the "add" method of the super class, which executes the "each" closure, which uses the "accessThisPrivateVariable".
I am new to groovy, so I think there must be an easy way to do this, because otherwise it seems that closures completely break the encapsulation of the private implementation done in the super class ... this seems to be a very common need (super class implementation referencing its own private variables)
I am using groovy 2.1.3
I found this to be a good reference describing how Groovy variable scopes work and applies to your situation: Closure in groovy cannot use private field when called from extending class
From the above link, I realized that since you have declared accessThisPrivateVariable as private, Groovy would not auto-generate a getter/setter for the variable. Remember, even in Java, private variables are not accessible directly by sub-classes.
Changing your code to explicitly add the getter/setters, solved the issue:
package com.test
import groovy.transform.CompileStatic
#CompileStatic
class ClosureScopeC {
private List<String> list = new ArrayList<String>()
private int accessThisPrivateVariable = 0;
int getAccessThisPrivateVariable() { accessThisPrivateVariable }
void setAccessThisPrivateVariable(int value ){this.accessThisPrivateVariable = value}
void add(String a) {
list.add(a)
println("before ${accessThisPrivateVariable} ${this.class.name}")
// do something with a closure
list.each {String it ->
if (it == a) {
// accessThisPrivateVariable belongs to ClosureScopeC
accessThisPrivateVariable++
}
}
println("after ${accessThisPrivateVariable}")
}
}
// this works fine
a = new ClosureScopeC()
a.add("abc")
a.add("abc")
// child class
class ClosureScopeD extends ClosureScopeC {
void doSomething(String obj) {
super.add(obj)
}
}
b = new ClosureScopeD()
b.doSomething("abc")
There is a simpler way, just make the access modifier (should rename the property really) to protected, so the sub-class has access to the property.. problem solved.
protected int accessThisProtectedVariable
To clarify on your statement of concern that Groovy possibly has broken encapsulation: rest assured it hasn't.
By declaring a field as private, Groovy is preserving encapsulation by intentionally suspending automatic generation of the public getter/setter. Once private, you are now responsible and in full control of how or if there is a way for sub-classes (protected) or all classes of objects (public) to gain access to the field by explicitly adding methods - if that makes sense.
Remember that by convention, Groovy ALWAYS calls a getter or setter when your codes references the field. So, a statement like:
def f = obj.someField
will actually invoke the obj.getSomeField() method.
Likewise:
obj.someField = 5
will invoke the obj.setSomeField(5) method.

Resources