Search code examples
groovyfunctional-programmingclosures

Pass method as parameter in Groovy


Is there a way to pass a method as a parameter in Groovy without wrapping it in a closure? It seems to work with functions, but not methods. For instance, given the following:

def foo(Closure c) {
    c(arg1: "baz", arg2:"qux")
}

def bar(Map args) {
    println('arg1: ' + args['arg1'])
    println('arg2: ' + args['arg2'])
}

This works:

foo(bar)

But if bar is a method in a class:

class Quux { 
    def foo(Closure c) {
        c(arg1: "baz", arg2:"qux")
    }

    def bar(Map args) {
        println('arg1: ' + args['arg1'])
        println('arg2: ' + args['arg2'])
    }

    def quuux() { 
      foo(bar)
    }
} 

new Quux().quuux()

It fails with No such property: bar for class: Quux.

If I change the method to wrap bar in a closure, it works, but seems unnecessarily verbose:

    def quuux() { 
      foo({ args -> bar(args) })
    }

Is there a cleaner way?


Solution

  • In addition to the method pointer operator (.&), for Groovy version 3.0.0 and above there's the equivalent, compatible, well known Java 8+ method reference operator (::).

    def foo(Closure c) {
        c(func: "foo")
    }
    
    def bar(Map args = [:]) {
        println "$args.func bar"
    }
    
    println foo(this::bar)
    

    Output:

    foo bar
    

    The method reference operator, as stated in Groovy's documentation:

    […] overlaps somewhat with the functionality provided by Groovy’s method pointer operator. Indeed, for dynamic Groovy, the method reference operator is just an alias for the method pointer operator. For static Groovy, the operator results in bytecode similar to the bytecode that Java would produce for the same context.