groovy-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jochen Theodorou <>
Subject Re: [Question] Variable Argument Lists, Named Arguments, Optional Parameters and Multiple assignment
Date Sat, 15 Aug 2015 08:07:59 GMT
Am 14.08.2015 19:10, schrieb Edinson E. PadrĂ³n Urdaneta:
> Greetings, everyone,
> I have a couple of questions I would like to address with you (if
> possible) and the best way to explain them (potentially) is through the
> following lines of code
>      def foo(Map kwargs, Object bar) { /*...*/ }                     //
> Instead of this ...
>      def foo(Object bar, Map kwargs) { /*...*/ }                     //
> ... wouldn't this be more clear ...

you can define both signatures no problem, but if you want the map 
semantics on method calls it has to be the first argument.

>      def foo(Object bar, Object[] args) { /*...*/ }                  //
> ... just like this one? ...
>      def foo(Object bar, Object[] args, Map kwargs) { /*...*/ }      //
> ... and we could combine both this way

No you would not be able to combine it this way. Java semantics require 
the vargs part to be last. This leaves only

def foo(Object bar, Map kwargs, Object[] args) { /*...*/ }
def foo(Map kwargs, Object bar, Object[] args) { /*...*/ }

as possible signatures.

>      def foo(Object a=null, Object b) { /*...*/ }                    //
> Shouldn't it rise an error?

"def foo(Object a=null, Object b)" causes groovy to produce the methods

def foo(Object b) {foo(null,b)}
def foo(Object a, Object b) { /*...*/ }

So unlike the map or vargs logic, this produces an overloaded method. 
And there is a defined right-to-left order for this

def foo(a=null,b=null){...}


def foo(){foo(null,null)}
def foo(a){foo(a,null)}
def foo(a,b){...}

Now keep in mind a few things:
  a) The map syntax existed before Java5 introduced vargs.
  b) Groovy can, because of its dynamic nature not reposition arguments 
easily and keep performance to a good level

Those two points have a lot of impact. Mainly (a) explains why vargs and 
the map version work quite different. But (b) explains that we had to 
decide on a fixed position to collect all those map arguments.

The Groovy compiler will for "foo(a:b, 1, b:c)" generate a call 
"foo([a:b,b:c],1)". For this kind of thing, you can basically only 
choose the end or the beginning. Had we chosen the end position, we 
would have gotten into conflict with vargs. Back then we did not know 
that, so it was more luck to do it like this. But in the end, the front 
position just looked more logically to us back then.

Also there is the difference in semantics that for foo(x,Object[] y) you 
can make a call foo(1) and get in y an empty array (all according to 
Java semantics), while for foo(Map m, y) a call foo(1) is not legal.

The later reason led to a combination of optional parameters and named 
arguments like this: def foo(Map m=[:],y), which will allow the call 
foo(1) and provide the map m with an empty map. Again the optional 
parameters part is pre Java5 and vargs.

And lastly point (b) also allows for the not using a type for the named 
arguments part: def foo(m){...} is a method that would accept 
"foo(a:b,b:c)" as well as foo(1) and is implicitly typed as Object. For 
the same reason you can use for example HashMap or LinkedHashMap instead 
of Map or Object. Map is advised for documentation purposes, but not 
required. Though I have to add, that HashMap and LinkedHashMap are 
implementation details and could in theory change.

>      def (int a, int b, int[] rest) = [1, 2, 3, 4]                   //
> Given this ...
>      assert a == 1 && b == 2 && rest == [3, 4]                      
> ... why something like this doesn't hold?

I guess simply because nobody had this idea back then. On the other 
hand... if the right side is an infinite (well up to Integer.MAX_VALUE) 
structure, then this kind of approach would lead to problems. And what 
would you expect if rest is not given a type?

like here:

def n = 0
def cl = {n2->n+=n2}

class Helper {
     def cl
     Object getAt(int i){cl(i)}

def h = new Helper(cl:cl)

def (a,b,c,d,e) = h
assert a == 0
assert b == 1
assert c == 3
assert d == 6
assert e == 10

Of course that is just playing around and nothing really useful

bye blackdrag

Jochen "blackdrag" Theodorou

View raw message