Closure with typed arguments in Groovy
Asked Answered
C

3

16

I'd like to be more explicit about my closures regarding their argument types. So I would write something like

List<Y> myCollect(List<X> list, Closure<X,Y> clos) { ... }

I know that Groovy won't use that type information, but Groovy++ may use it at compile time. Can this be be achieved (other than putting it into a comment)?

UPDATE: The title may sound misleading, but I thought the above example would make it clearer. I'm interested in specifying types of a closure which is the argument of some function. Suppose, I want to redefince the built-in collect. So I'm interested in writing myCollect, not in writing clos. What I want to achieve is get compile time errors

myCollect(['a', 'ab'], { it / 2 }) // compile error
myCollect(['a', 'ab'], { it.size() })  // OK 
Crosley answered 15/4, 2011 at 19:46 Comment(3)
In the type Closure<V>, the V represents the return value of the closure, not its parameters. As such, it wouldn't make sense to have a Closure<V, X> since you can't return two values.Sennacherib
I mean Closure<X,Y> to accept a single X as input and returns Y. So it can be applied to the items of List<X>. I updated the return type of the function.Crosley
now the accepted answer should be the one from Richard Vowles: https://mcmap.net/q/734062/-closure-with-typed-arguments-in-groovy since it regards the redefinition of the closure interface/function and related type checks.Preoccupy
C
10

You can define the types of a closure's parameters, but the syntax shown above is incorrect. Here is a closure without parameter types:

def concatenate = {arg1, arg2 ->
  return arg1 + arg2
}

And here is the same closure with parameter types

def concatenate = {String arg1, String arg2 ->
  return arg1 + arg2
}

I know that Groovy won't use that type information, but Groovy++ may use it at compile time.

Groovy does do some compile-time type checking, but not as much as Groovy++ (or Java). Even if the type information is not used at compile-time it will be checked at runtime, and is also valuable as a form of documentation.

Crock answered 18/4, 2011 at 9:21 Comment(2)
please, see my update. Of what type is your concatenate? Is it Closure<String,String,String>? Or what?Crosley
I accept this answer not because I'm happy with it, but this is the only one :( Maybe, my question wasn't clear enough.Crosley
Y
4

For anyone still looking for the answer: have a look at @ClosureParams, which provides IDE hints as to the expected closure parameter types

Yount answered 29/1, 2022 at 12:13 Comment(0)
C
3

I presume you aren't using Groovy++ anymore, but even if you are this may work. It certainly works for statically typed Groovy 2.x

interface Z {
  void callback(X x, Y y)
}

List<Y> myCollect(List<X> list, Z clos) { 
  ... 

  clos.callback(x, y)
}

the caller then calls it with the normal:

List<Y> object.myConnect(list) { X x, Y y -> 
}

If you leave a parameter out and have @CompileStatic, the compiler picks up missing params or bad types.

This works because a 1 method interface is equivalent to a closure in Groovy.

Casia answered 27/5, 2014 at 10:52 Comment(1)
it also works by using Java's functional interfaces as the type of the argument, like Function (one-arg, one-return-value), BiFunction (two-args, one-return-value) or Consumer (one-arg, no return value).Arlon

© 2022 - 2024 — McMap. All rights reserved.