You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@groovy.apache.org by "David M. Karr" <da...@gmail.com> on 2016/04/18 19:50:27 UTC

Required named parameters in constructor?

First of all, I'm not attempting a "Groovy vs. anything else" argument, 
so put away the flamethrowers.  I find myself defending Groovy when I 
have the chance.

I was, however, reading a Ruby book, as I've never looked at it before, 
as I found I had to learn about Puppet, and I concluded that you can't 
work effectively with robust Puppet modules without understanding Ruby.

As a result, I found myself paying attention to to how Ruby features map 
to Groovy.  I'm not talking about syntax, just functional features.

I got to the point in the Ruby book where it mentioned that you could 
set particular keyword parameters (like Groovy Named Parameters) to be 
required.  I can't think of a "direct" way to map this to Groovy.  I 
suppose you could implement an "ad hoc" strategy that throws if 
particular values aren't set.  Is there a more concise way?

Just as an observation, I also note that Ruby allows mixing both 
"positional" and "named" parameters in the same constructor call.

Re: Required named parameters in constructor?

Posted by Guillaume Laforge <gl...@gmail.com>.
There's actually the new MapConstructor AS transformation which we could
use here:
https://speakerdeck.com/glaforge/a-groovy-journey-in-open-source-greach-2016?slide=130
https://github.com/apache/groovy/blob/master/src/main/groovy/transform/MapConstructor.java

You'd define a pre-condition, checking that the required params are indeed
present.

Guillaume


On Tue, Apr 19, 2016 at 8:20 AM, Jochen Theodorou <bl...@gmx.org> wrote:

> On 19.04.2016 05:21, emmanuel r wrote:
>
>> You know, I bet that could be done with an ast transformation. Using it
>> could look like this:
>>
>> @RequiredConstructorParameters(parameters = ['a'])
>> class Foo {
>>      String a
>>      String b
>> }
>>
>
> well, you could try TupleConstructor for example
>
> be Jochen
>
>
>
>


-- 
Guillaume Laforge
Apache Groovy committer & PMC Vice-President
Product Ninja & Advocate at Restlet <http://restlet.com>

Blog: http://glaforge.appspot.com/
Social: @glaforge <http://twitter.com/glaforge> / Google+
<https://plus.google.com/u/0/114130972232398734985/posts>

Re: Required named parameters in constructor?

Posted by Jochen Theodorou <bl...@gmx.org>.
On 19.04.2016 05:21, emmanuel r wrote:
> You know, I bet that could be done with an ast transformation. Using it
> could look like this:
>
> @RequiredConstructorParameters(parameters = ['a'])
> class Foo {
>      String a
>      String b
> }

well, you could try TupleConstructor for example

be Jochen




RE: Required named parameters in constructor?

Posted by emmanuel r <go...@gmail.com>.
You know, I bet that could be done with an ast transformation. Using it
could look like this:

@RequiredConstructorParameters(parameters = ['a'])
class Foo {
    String a
    String b
}
On Apr 18, 2016 2:33 PM, "Winnebeck, Jason" <Ja...@windstream.com>
wrote:

> I think Groovy is limited here to the JVM's features. It is not possible
> to implement named parameters properly since you don't know the method
> names (except when using an optional compiler param in Java 1.8+), so there
> is not truly named parameters in Groovy. Instead, all of the named
> parameters are converted into a Map. And Groovy does allow positional and
> named parameters in the same call, where all of the named parameters are
> collected into a single map.
>
> As far as I know the best solution for enforcing the named parameters is
> just to check for their presence in the map manually in the function itself.
>
> The only place I see in Groovy where "named parameters" actually works
> well is when constructing an object -- the names parameters all turn into
> setter calls. It is possible to abuse this so that Groovy code would fail
> when trying to set non-existant parameters, but it doesn't solve the
> required parameters issue without manual code. It also has the benefit of
> code completion in IDE and type checking. Specifically I am talking about:
>
> class FooCall {
>   String a
>   String b
>
>   void call() {
>     if (!a || !b)
>       throw new IllegalArgumentException("a and b are required");
>     println "call $a $b"
>   }
> }
>
> new FooCall(a:"a", b:"b")()
>
> However, the code is very awkward. That's not much better than:
>
> REQ_PARAMS = ['a', 'b'] as Set
> ALL_PARAMS = REQ_PARAMS + ['c'] as Set
>
> void foo(Map params) {
>   params = params ?: [:]
>   if (!params.keySet().containsAll(REQ_PARAMS))
>     throw new IllegalArgumentException("Missing required parameters
> ${REQ_PARAMS - params.keySet()}")
>   if (params.keySet() - ALL_PARAMS)
>     throw new IllegalArgumentException("Extra parameters ${params.keySet()
> - ALL_PARAMS}")
>
>   println "foo $params"
> }
>
> foo(a:1, b:1, c:1)
>
> Jason
>
> -----Original Message-----
> From: David M. Karr [mailto:davidmichaelkarr@gmail.com]
> Sent: Monday, April 18, 2016 1:50 PM
> To: users@groovy.apache.org
> Subject: Required named parameters in constructor?
>
> First of all, I'm not attempting a "Groovy vs. anything else" argument, so
> put away the flamethrowers.  I find myself defending Groovy when I have the
> chance.
>
> I was, however, reading a Ruby book, as I've never looked at it before, as
> I found I had to learn about Puppet, and I concluded that you can't work
> effectively with robust Puppet modules without understanding Ruby.
>
> As a result, I found myself paying attention to to how Ruby features map
> to Groovy.  I'm not talking about syntax, just functional features.
>
> I got to the point in the Ruby book where it mentioned that you could set
> particular keyword parameters (like Groovy Named Parameters) to be
> required.  I can't think of a "direct" way to map this to Groovy.  I
> suppose you could implement an "ad hoc" strategy that throws if particular
> values aren't set.  Is there a more concise way?
>
> Just as an observation, I also note that Ruby allows mixing both
> "positional" and "named" parameters in the same constructor call.
>
> ----------------------------------------------------------------------
> This email message and any attachments are for the sole use of the
> intended recipient(s). Any unauthorized review, use, disclosure or
> distribution is prohibited. If you are not the intended recipient, please
> contact the sender by reply email and destroy all copies of the original
> message and any attachments.
>

RE: Required named parameters in constructor?

Posted by "Winnebeck, Jason" <Ja...@windstream.com>.
I think Groovy is limited here to the JVM's features. It is not possible to implement named parameters properly since you don't know the method names (except when using an optional compiler param in Java 1.8+), so there is not truly named parameters in Groovy. Instead, all of the named parameters are converted into a Map. And Groovy does allow positional and named parameters in the same call, where all of the named parameters are collected into a single map.

As far as I know the best solution for enforcing the named parameters is just to check for their presence in the map manually in the function itself.

The only place I see in Groovy where "named parameters" actually works well is when constructing an object -- the names parameters all turn into setter calls. It is possible to abuse this so that Groovy code would fail when trying to set non-existant parameters, but it doesn't solve the required parameters issue without manual code. It also has the benefit of code completion in IDE and type checking. Specifically I am talking about:

class FooCall {
  String a
  String b
  
  void call() {
    if (!a || !b)
      throw new IllegalArgumentException("a and b are required");
    println "call $a $b"
  }
}

new FooCall(a:"a", b:"b")()

However, the code is very awkward. That's not much better than:

REQ_PARAMS = ['a', 'b'] as Set
ALL_PARAMS = REQ_PARAMS + ['c'] as Set

void foo(Map params) {
  params = params ?: [:]
  if (!params.keySet().containsAll(REQ_PARAMS))
    throw new IllegalArgumentException("Missing required parameters ${REQ_PARAMS - params.keySet()}")
  if (params.keySet() - ALL_PARAMS)
    throw new IllegalArgumentException("Extra parameters ${params.keySet() - ALL_PARAMS}")
  
  println "foo $params"
}

foo(a:1, b:1, c:1)

Jason

-----Original Message-----
From: David M. Karr [mailto:davidmichaelkarr@gmail.com] 
Sent: Monday, April 18, 2016 1:50 PM
To: users@groovy.apache.org
Subject: Required named parameters in constructor?

First of all, I'm not attempting a "Groovy vs. anything else" argument, so put away the flamethrowers.  I find myself defending Groovy when I have the chance.

I was, however, reading a Ruby book, as I've never looked at it before, as I found I had to learn about Puppet, and I concluded that you can't work effectively with robust Puppet modules without understanding Ruby.

As a result, I found myself paying attention to to how Ruby features map to Groovy.  I'm not talking about syntax, just functional features.

I got to the point in the Ruby book where it mentioned that you could set particular keyword parameters (like Groovy Named Parameters) to be required.  I can't think of a "direct" way to map this to Groovy.  I suppose you could implement an "ad hoc" strategy that throws if particular values aren't set.  Is there a more concise way?

Just as an observation, I also note that Ruby allows mixing both "positional" and "named" parameters in the same constructor call.

----------------------------------------------------------------------
This email message and any attachments are for the sole use of the intended recipient(s). Any unauthorized review, use, disclosure or distribution is prohibited. If you are not the intended recipient, please contact the sender by reply email and destroy all copies of the original message and any attachments.