groovy-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Jason Winnebeck (JIRA)" <>
Subject [jira] [Commented] (GROOVY-7956) Allow @DelegatesTo on named arguments
Date Thu, 06 Oct 2016 16:26:20 GMT


Jason Winnebeck commented on GROOVY-7956:

I like the MapArguments or NamedArguments name better than DelegatesTo or Properties. I didn't
know about the linked bsideup repo for the AST transform, that's a cool idea that you can
just take the final object, then Groovyc has the ability to decide whether to actually create
a literal HashMap, or implement essentially named parameters.

I'm not a fan of {{@Properties([ x: Integer, y: Integer ])}}, but I suggested that because
I could easily see people complaining about having to create classes for nothing besides type
definitions, especially in a language like Groovy after all, which is encouraging excessive
typing (I realize this is a static compiler request though). If anything, I was inspired by
JSDoc and closure compiler where you specify the fields of an object in the {{@param}} field,
but if you get past a few fields (like x/y for a point object), it gets so ridiculous that
you just say "object".

C├ędric's {{@NamedArguments}} parameter annotation from what I can tell is a better, more
direct form of the {{@MapArguments}} prototype linked by Paul King. However, maybe "NamedArguments"
could be better reserved for a true named arguments functionality like we see in other classes.
How is this for a proposal:

class Point { int x, y }

//Give type information to IDEs and static type checker only. There's no AST transform or
runtime change.
@interface MapDescription {
	Class value()
	//If people complain and want inline type we could define a "description" property then you
use value or description

//AST transform that generates an extra method taking a Map in place of the annotated parameter
//Static compiler replaces literal calls without temporary intermediate Map object, instead
doing new + setter calls
@interface MapArgument {}

//AST transform that generates a method taking only a Map that calls original method with
//Static compiler replaces calls with direct method calls (not creating temporary Map)
//Risk: change in method signature breaks binary compatibility with @CompileStatic
@interface NamedArguments {}

class X {
	void methodDescribed(@MapDescription(Point) Map point) {
		println "$p.x, $p.y"

	void method(@MapArgument Point p, int z) {
		println "$p.x, $p.y, $z"

	//Method generated by MapArguments AST:
	void method(Map p, int z) {
		method(p as Point, z)

	void callMethod() {
		method(x:1, y:2, 3)
		//static compiler generates: Point p = new Point(); p.setX(1); p.setY(2); method(p, 3)
		//dynamic compiler generates same code it does today -- create a map and invoke method with
map and 3

	void method2(int x, int y) {
		println "$x, $y"

	//Method generated by NamedArguments AST
	void method2(Map m) {
		method(m.x as int, m.y as int)
	void callMethod2() {
		method2(x: 1, y: 2)
		//static compiler generates method2(1, 2)
		//dynamic compiler generates same code as previously, create map and invoke method

The MapDescription handles the request of this request directly, while the other 2 forms improve
this case for static compilation both on the callee side (by retaining original method taking
object or primitive parameters) and on the caller side (by eliminating the need for HashMap
and primitives boxing).

> Allow @DelegatesTo on named arguments
> -------------------------------------
>                 Key: GROOVY-7956
>                 URL:
>             Project: Groovy
>          Issue Type: New Feature
>          Components: GEP
>            Reporter: Graeme Rocher
> In order to aid static compilation for builders we have {{@DelegatesTo}} which allows
statically compiled code to know what the delegate of a closure is.
> This proposal is to allow {{@DelegatesTo}} on {{Map}} types such that IDEs and the static
compiler can resolve the target type the named arguments are to be used on.
> For example:
> {code}
> class Farm {
>      void animal(@DelegatesTo(Animal) Map arguments, @DelegatesTo(AnimalBuilder) Closure
callable) {
>              def animal = new Animal(arguments)
>              // handle closure
>     }
> } 
> class Animal { String name }
> {code}
> The following code would then fail to compile :
> {code}
> def farm = new Farm()
> // compilation failure, no name property on Animal
> farm.animal(nam: "Dog")  { 
> }
> {code}
> It would then be down to IDEs to also provide support for code completion etc.

This message was sent by Atlassian JIRA

View raw message