Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-10261

@NamedVariant: Default parameters on ctor/method are ignored when passing some named parameters



    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 3.0.9
    • 4.0.0-beta-2, 2.5.16, 3.0.10
    • Compiler
    • IntelliJ 2021.1.1 x64
      WIN 10


      • When using named paramters on an @NamedVariant annotated ctor or method, default values for parameters not passed are ignored and the parameters are set to null instead
      • This does not occur when no paramaters are passed, or (trivially) if all named parameters are passed
      • Default parameters are a powerful feature of Groovy, not having them supported requires one to
        1. Treat parameters who cannot have null as an allowed value who are passed as null as having the default value (leading to a lot of clutter / boiler plate code)
        2. Parameters for which null is a valid value, special-meaning e.g. EMPTY instances have to be implemented and given as the default parameter value, to be mapped to the actual value as with the null values above, which evidently is even more cumbersome & inelegant
      • Sample code
        • Note: assertEquals is used since at least in IntelliJ it supplies a link to the integrated text diff viewer, allowing to conevniently compare the expected and actual results:
          import groovy.transform.NamedVariant
          import org.junit.Test
          import simple.groovy.helper.Foo
          import simple.groovy.helper.NamedVariantTestClass
          import static org.junit.Assert.assertEquals
          //@CompileStatic // compile-static or not does not matter
          class NamedVariantTest2 {
              @Test void namedVariantCtorBug_DefaultArgumentsAreIgnored() {
                  final resultList = [
                      new NamedVariantTestClass(),
                      new NamedVariantTestClass(text:"cba"),
                      new NamedVariantTestClass(text:"cba", foo:new Foo(8765,'Oof')),
                      new NamedVariantTestClass(text:"cba", foo:new Foo(8765,'Oof'),  number:4321),
                      //new NamedVariantTestClass("cba", foo:new Foo(321,'foot'),  number:7777)
                  // Fails: all non-given ctor arguments are incorrectly set to null instead of being given their default value, unless all or no arguments are passed.
                  assertEquals resultList.join('\n'),
          NVTC(number=1234, text=abc, foo=Foo(5678,'Foo'))
          NVTC(number=1234, text=cba, foo=Foo(8765,'Oof'))
          NVTC(number=1234, text=cba, foo=Foo(8765,'Oof'))
          NVTC(number=4321, text=cba, foo=Foo(8765,'Oof'))
              @Test void namedVariantMethodBug_DefaultArgumentsAreIgnored() {
                  final resultList = [
                      namedVariantTestMethod(text:"cba", foo:new Foo(8765,'Oof')),
                      namedVariantTestMethod(text:"cba", foo:new Foo(8765,'Oof'),  number:4321)
                  resultList.each { println it }
                  // Fails: all non-given method arguments are incorrectly set to null instead of being given their default value, unless all or no arguments are passed.
                  assertEquals resultList.join('\n'),
          nvtm(number=1234, text=abc, foo=Foo(5678,'Foo'))
          nvtm(number=1234, text=cba, foo=Foo(8765,'Oof'))
          nvtm(number=1234, text=cba, foo=Foo(8765,'Oof'))
          nvtm(number=4321, text=cba, foo=Foo(8765,'Oof'))
              @NamedVariant String namedVariantTestMethod(Integer number = 1234, String text = "abc", Foo foo = new Foo(5678, 'Foo')) {
                  "nvtm(number=$number, text=$text, foo=$foo)"
      class NamedVariantTestClass {
          final Integer number; final String text; final Foo foo
          @NamedVariant NamedVariantTestClass(Integer number = 1234, String text = "abc", Foo foo = new Foo(5678, 'Foo')) {
              this.number = number; this.text = text; this.foo = foo
          @Override String toString() { "NVTC(number=$number, text=$text, foo=$foo)" }
      class Foo {
          final Number x; final String s
          Foo(Number x, String s) { this.x = x; this.s = s }
          @Override String toString() { "Foo($x,'$s')" }


        Issue Links



              paulk Paul King
              emge mgroovy
              0 Vote for this issue
              2 Start watching this issue



                Time Tracking

                  Original Estimate - Not Specified
                  Not Specified
                  Remaining Estimate - 0h
                  Time Spent - 0.5h