Skip to content

Instantly share code, notes, and snippets.

@purplefox
Created March 23, 2012 08:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save purplefox/2168524 to your computer and use it in GitHub Desktop.
Save purplefox/2168524 to your computer and use it in GitHub Desktop.
Groovy question
I have a method on a class which takes a Closure as an argument:
class Foo {
void register(Closure handler)
}
The closure represents a handler that will be called back some time in the future
In most cases users will specify the Closure directly when calling it:
new Foo().register { println "in handler" }
But there are other objects that can act as handlers and that I want to be able to pass to register too
E.g. I would like to do something like
class MyHandler implements Closure {
void call() {
println "in handler"
}
}
But this doesn't work since Closure is not interface. I've tried extending it too, and that doesn't seem to work.
Any ideas?
@jfaissolle
Copy link

Just take a Callable as parameter for your register method. Your handler will simply have to implement Callable.

@melix
Copy link

melix commented Mar 23, 2012

I think you may want to reverse the logic. You could have:

class Foo {
void register(Handler handler)
}

interface Handler {
void handle()
}

class MyHandler implements Handler { ... }

then in Groovy code:

new Foo().register({ 'handle'} as Handler)

And if you want to avoid the explicit "as" coercion, you can add an alternate method to class Foo. If it is written in Groovy:

class Foo {
void handle(Handler handler) { ... }
void handle(Closure cl) { handle(cl as Handler) }
}

Or, if Foo is written in Java:

public class Foo {
public void handle(Handler handler) { ... }
public void handle(Closure cl) { handle(DefaultGroovyMethods.asType(cl, Handler.class); }
}

The main advantage of this technique is that you are not limited to run() or call() methods: you can add as many methods as you want, and if the interface has more than one method, coercion from map of closure to interface is still possible :)

@purplefox
Copy link
Author

Julien - do you mean java.util.concurrent.Callable?

Cedric - exposing the Handler class in the API is actually what I am trying to avoid. I am wrapping the vert.x Java API with Groovy and in the Java API handlers are represented as instances of the Handler interface, which is normally implemented by the user as anonymous classes, since Java doesn't have closures.
One of the interesting things about Groovy to me is I can use closures, having to co-erce them every time to Handler seems pretty ugly to me.

In Ruby I would use instance of the Proc class to do this.

@jfaissolle
Copy link

Yes, I was meaning java.util.concurrent.Callable but it is not applicable since handlers take an event as parameter.

@pledbrook
Copy link

Tim, why not just require a particular method on objects that are handlers and not worry about whether they implement a particular interface or not? You could just require all handler classes to implement the call() method for example. Alternatively, why not have:

class Foo {
    void register(handler) {
        delegate.register(handler as Handler)
    }
}

That would work if the handler argument were a closure or an instance of Handler.

@purplefox
Copy link
Author

Peter,

yup, makes sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment