Using a Closure as an argument to a superclass constructor - groovy

I seem unable to use a Closure as a parameter to a superclass constructor when it is specified inline.
class Base {
def c
Base(c) {
this.c = c
}
void callMyClosure() {
c()
}
}
class Upper extends Base {
Upper() {
super( { println 'called' } )
}
}
u = new Upper()
u.callMyClosure()
The compilation fails with the message Constructor call must be the first statement in a constructor..
I realize this a somewhat strange use-case, and I can design around it for the time being. But I'm interested, is this is to be expected? Or have I got the syntax incorrect?

I think that the problem is related to the fact that Groovy turns the constructor into something different while trying to compile it as a Java class. Maybe the closure definition is expanded before the call to super generating that error.
A workaround is to define the closure outside the constructor itself:
class Base {
def c
Base(c) {this.c = c}
void callMyClosure() {
c()
}
}
class Upper extends Base {
static cc = {println 'called'}
Upper() {
super(cc)
}
}
u = new Upper()
u.callMyClosure()
It's not so nice but at least it works.. another way could be to define the closure by using a normal new Closure(...) syntax

It might be confusing a closure and a block...can you try
super( { -> println 'called' } )

Related

custom cast function and abstracts

This code outputs Null<_Test.Bar_Impl_>. I wanted it to output Foo but I see why it does not work that way. But may be I can somehow overcome this limitation.
My primary goal is to create function that will work like cast, but return null instead of throwing exception. And it should work with abstracts.
class Foo {
}
abstract Bar(Foo) {
}
class MyCast {
inline static public function doCast<T>(value: Any, type: Class<T>): Null<T> {
return Std.is(value, type) ? cast value : null;
}
}
class Test {
static function main() {
$type(MyCast.doCast(null, Bar));
}
}
Actually that cannot work at all like that, since Std.is(value, AbstractType) will always fail because the abstract does not exist any more at runtime.
See https://try.haxe.org/#1Afb5, and especially:
Use #:forward to access foo from Bar instances (forward doc)
Use from Foo to safe cast Foo instances into Bar instances (see implicit cast doc) (note that this feature on itself may be exactly what you were trying to achieve: https://try.haxe.org/#cc903)

groovy immutable object with parent class

I have two immutable groovy classes that have a few shared values that I'm trying to abstract to a parent class. However when I create the following, the second test case always fails. Although everything compiles correctly and no error is thrown at runtime, when I assign the parent property int he constructor, it is never set, resulting in a null value. I havent found any documentation that forbids this, but I'm wondering is this even possible? I've tried a number of configuration of Annotations and class-types (e.g. removing abstract from the parent) but nothing seems to work short of just removing the #Immutable tag altogether.
abstract class TestParent {
String parentProperty1
}
#ToString(includeNames = true)
#Immutable
class TestChild extends TestParent {
String childProperty1
String childProperty2
}
class TestCase {
#Test
void TestOne() {
TestChild testChild = new TestChild(
childProperty1: "childOne",
childProperty2: "childTwo",
parentProperty1: "parentOne"
)
assert testChild
assert testChild.parentProperty1
}
}
Based on the code for the ImmutableASTTransformation, the Map-arg constructor added by the createConstructorMapCommon method does not include a call to super(args) in the method body.
which means that immutable classes are self contained by default
Now if you want to do it you need to use composition instead of inheritance and this is an example of how you can do it :
import groovy.transform.*
#TupleConstructor
class A {
String a
}
#Immutable(knownImmutableClasses=[A])
class B {
#Delegate A base
String b
}
def b = new B(base: new A("a"), b: "b")
assert b.a
i hope this will help :)

Unification and implicit cast of the type parameter

class Base, and class Ext extends Base.
class B<T> with typed method foo<T>(value:T)
Why B<Base>.foo doest not accept instance of B<Ext> (implicit downcast of the type parameter?) by default?
Here is an example
http://try.haxe.org/#d443f
class Test {
static function main() {
var bExt = new B(new Ext());
var bBase = new B(new Base());
bBase.foo(bExt);
//ofc
//bBase.foo(cast bExt);
}
}
class B<T>
{
public function new(v:T)
{
}
public function foo(v:B<T>)
{
//
}
}
class Base {
public function new(){}
}
class Ext extends Base {
public function new(){
super();
}
}
Is there any way to trigger implicit cast of the type parameter for B.foo?
There are three ways to interpret and answer your question:
1. foo(v:B<T>):
This is your example and it doesn't compile because T isn't allowed to be be variant. It happens because of the very existence of foo and because allowing bBase.foo(bExt), that is, unifying bExt with bBase, will then allow bBaseOfbExt.foo(bBase).
It is the fact that foo exists and that it can potentially modify the type that makes the bExt unification with bBase unsafe; you can see a similar (but maybe clearer) explanation in the manual, using arrays: type system – variance.
2. foo(v:T):
This is closer to what's on the body of your question (but not in the example) and it works fine.
3. foo<A>(v:B<A>):
Finally, if you have a type parameterized method, it also works, but you'd probably face other variance issues elsewhere.

Groovy and Java Callbacks / Lambdas (Closures with a type)

This is a callback I have in Java (future is a Mongo's SingleFutureResult):
future.register(new SingleResultCallback<ArrayList<Document>>() {
#Override
void onResult(ArrayList<Document> documents, MongoException e) {
//do something
}
})
With Java 8 I can use Lambdas to make it look like this:
future.register((documents, e) -> {
//do something
});
Neat. However, I would like to call that Java method within a Groovy class. I know Groovy does currently not support jdk8 lambda's syntax, but the docs always stress that they have closures instead. If I try to use a closure in such a case it fails, as the closure is of type Closure, and not of type SingleResultCallback. Is there a way to have something like a closure with a different type? Is there any other way to make this work in a nice way? I know I can use the first solution, but that looks pretty weird within a groovy class.
Use Groovy's closure syntax:
future.register( { documents, e ->
//do something
});
If there is ambiguity in a register method overload, it might need as SingleResultCallback after the closure declaration:
future.register { documents, e -> } as SingleResultCallback
This is an ambiguity scenario:
interface SingleResultCallback<T> {
def onResult(T result)
}
interface Callback { def onResult(obj) }
class Future {
void register(SingleResultCallback s) {
println "registered: ${s.onResult(10)}"
}
void register (Callback r) {
println "runnable=${r.onResult()}"
}
}
new Future().register { it ** 2 }
Which fails with:
Caught: groovy.lang.GroovyRuntimeException:
Ambiguous method overloading for method Future#register.
Cannot resolve which method to invoke for [class Sam$_run_closure1] due
to overlapping prototypes between:
[interface Callback]
[interface SingleResultCallback]
And if SingleResultCallback had more than one method, a map coercion is a nice way to deal with it:
interface SingleResultCallback<T> {
def onResult(T result)
def onError
}
class Future {
def register(SingleResultCallback s) {
"registered: ${s.onResult(10)}"
}
}
assert new Future().register(
[onResult: { it ** 2 } ] as SingleResultCallback ) == "registered: 100"
I know it has been a while since the question was made, and it's already replied, but i would also to add this example using Groovy Closure as callback (to see more go at https://groovy-lang.org/closures.html).
Groovy also support Closure as an Object, for instance:
Closure callback = { println 'Done!' }
callback()
The output would be:
Done!
Above it's just another example:
def callbackList(){
def list = ["RICE", "BEANS", "EGGS"]
iterableList(list, { elem ->
println elem
})
}
def iterableList(list, callback){
list.each {
callback(it)
}
}
The output would be:
RICE
BEANS
EGGS

Groovy: Got StackOverflowError when override invokeMethod with a closure

I'm trying to enhance my Grails project with Groovy AOP approach. However I always got StackOverflowError if I override invokeMethod with a closure. Here is my test code, I can reproduce the error with groovy 2.1.3, thanks!
class A implements GroovyInterceptable
{
void foo(){
System.out.println( "A.foo");
}
}
class B extends A
{
void foo(){
System.out.println( "B.foo");
super.foo();
}
}
def mc = B.metaClass;
mc.invokeMethod = { String name, args ->
// do "before" and/or "around" work here
try {
def value = mc.getMetaMethod(name, args).invoke(delegate, args)
// do "after" work here
return value // or another value
}
catch (e) {
// do "after-throwing" work here
}
}
B b = new B();
b.foo();
Looks like, if you have a call to super() then metaClass uses the cache to find the method and throws a StackOverflow eventually. In that case if you metaClass A instead of B, it all works fine.
def mc = A.metaClass
I can infer it this way, class implementing GroovyInterceptable directly should override invokeMethod.
#Source MetaClassImpl

Resources