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

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

    XMLWordPrintableJSON

Details

    • 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
      AdoptOpenJDK-11.0.11+9
      WIN 10

    Description

      • 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'))
                  """.trim()
              }
          
              @Test void namedVariantMethodBug_DefaultArgumentsAreIgnored() {
                  final resultList = [
                      namedVariantTestMethod(),
                      namedVariantTestMethod(text:"cba"),
                      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'))
                  """.trim()
              }
          
              @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')" }
      }
      

      Attachments

        Issue Links

          Activity

            People

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

              Dates

                Created:
                Updated:
                Resolved:

                Time Tracking

                  Estimated:
                  Original Estimate - Not Specified
                  Not Specified
                  Remaining:
                  Remaining Estimate - 0h
                  0h
                  Logged:
                  Time Spent - 0.5h
                  0.5h