Reputation: 144
How can I call the label
function and set a closure to it as the last parameter in this way? This code works only if I call label
with parentheses but I don't need them. Is it possible to set the closure into function without them?
label = { name, callback ->
callback()
}
label "lbl" { // not works
println "call $it"
}
label ("lbl") { // works
println "call $it"
}
Upvotes: 6
Views: 1714
Reputation: 42224
If you don't want to use parentheses then you have to split closure arguments with ,
to tell the compiler that you want to execute label
with following two parameters:
label "lbl", {
println "call $it"
}
This notation is equivalent of:
label("lbl", {
println "call $it"
})
Groovy has this syntactic sugar that allows you passing closure outside parenthesis when closure is the last parameter of a function prototype, that's why following notation works:
label ("lbl") {
println "call $it"
}
But it is still an equivalent of the ones mentioned earlier.
How to make
label "lbl" { }
a valid statement?If you really want to compile code like:
label "lbl" { println "call $it" }
you need to be aware of one thing - such notation is an equivalent of:
label("lbl" { println "call $it" })
It means that there is a function
label
that accepts single parameter - a value returned fromlbl
function that accepts a single parameter - closure. The implementation of these functions might look like this:def label = { value -> // do something with value println "The value accepted by label function is '${value}'" } def lbl = { callback -> callback?.call() } label "lbl" { println "call $it" }
It compiles and it prints following output to console:
call null The value accepted by label function is 'null'
Of course as you can see you have to implement method
lbl
and in most cases this is very limiting - you can't calllabel
function with any parameter different thanlbl
. You could implement Groovy'smethodMissing(name, args)
function that gets called whenever non-existing method gets invoked. Consider following example:def methodMissing(String name, args) { if (args.length == 1 && args[0] instanceof Closure) { println "Running missing method '${name}'" return args[0].call() } throw new MissingMethodException(name, this.class, args) } def label = { value -> // do something with value println "The value accepted by label function is '${value}'" } def lbl = { callback -> callback?.call() } label "lbl" { println "call $it" } label "test" { println "nothing" }
In this case when
label "test" { println "nothing" }
gets invoked, Groovy usesmissingMethod
because methodtest
does not exist in the runtime context.call null The value accepted by label function is 'null' Running missing method 'test' nothing The value accepted by label function is 'null'
However it doesn't mean, that you can think about this as an equivalent of getting rid of coma separator or parenthesis from your code. This is an example of a simple DSL written with Groovy that uses
methodMissing
mechanism to satisfy non-existing methods invocation. This last example is actually the same as:label("test" { println "nothing" })
A function that expects a single argument and in this case we provide it as a result of
test
method invocation with a single parameter{ println "nothing" }
.I would strongly suggest accepting the fact that Groovy requires you to separate function arguments with a coma and don't use such DSL to remove coma or parenthesis from the code. Groovy DSL is very powerful and you have to know what you are doing when you decide using this tool in your code. For instance, think about what happens if you call:
label "test" { println "something" }
and for some reason a method defined as a following closure:
def test = { int num -> num + 2 }
exists in your class. You will start getting exceptions, because
methodMissing
is not called anymore in this case. Methodtest
exists, but it does not have a signature that accepts a single closure.
Upvotes: 9