groovy
  1. groovy
  2. GROOVY-6134

Make @DelegatesTo support mapping to generic type argument

    Details

    • Type: Improvement Improvement
    • Status: Closed Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 2.1.3
    • Fix Version/s: 2.2.0-beta-1
    • Component/s: None
    • Labels:
      None
    • Number of attachments :
      0

      Description

      Following the discussion at https://gist.github.com/alkemist/5429603, it would be interesting if Groovy allowed @DelegatesTo to map onto a generic type argument.

      For example:

      public <T> Object map(@DelegatesTo.Target List<T> target,  @DelegatesTo(genericTypeIndex=0) Closure arg) {
          arg.delegate = target.join('')
          arg()
      }
      def test() {
          def result
          map(['f','o','o']) {
              result = toUpperCase()
          }
      
          result
      }
      assert 'FOO'==test()
      

        Activity

        Hide
        Peter Niederwieser added a comment -

        My expectation is that def <T> T configure(@DelegatesTo.Target Class<T> target, @DelegatesTo(genericTypeIndex=0) Closure closure) does the trick. But currently, neither the delegate type nor the return type of {{configure(Car)

        { brand = "BMW" }

        }} is inferred correctly.

        Show
        Peter Niederwieser added a comment - My expectation is that def <T> T configure(@DelegatesTo.Target Class<T> target, @DelegatesTo(genericTypeIndex=0) Closure closure) does the trick. But currently, neither the delegate type nor the return type of {{configure(Car) { brand = "BMW" } }} is inferred correctly.
        Hide
        Peter Niederwieser added a comment -

        Interesting. I could swear this didn't work for me. Will have to investigate.

        Show
        Peter Niederwieser added a comment - Interesting. I could swear this didn't work for me. Will have to investigate.
        Hide
        CÚdric Champeau added a comment -

        This is exactly what I've written and it passes, so I suspect it only works on master and 2.1.7-SNAPSHOT (lots of generics fixes in there).

        P.S: Tested on 2.1.6 and it fails, so my guess seems to be right, 2.1.7 will infer correctly.

        Show
        CÚdric Champeau added a comment - This is exactly what I've written and it passes, so I suspect it only works on master and 2.1.7-SNAPSHOT (lots of generics fixes in there). P.S: Tested on 2.1.6 and it fails, so my guess seems to be right, 2.1.7 will infer correctly.
        Hide
        Peter Niederwieser added a comment -

        After double-checking, above example does work in GroovyConsole 2.2.0-beta-1, which is great. However, it apparently stops working once configure and foo are declared in different classes. For example, the following isn't working:

        @groovy.transform.CompileStatic
        class Car {
          String brand
        }
        
        @groovy.transform.CompileStatic
        class Builder {
         def <T> T configure(@DelegatesTo.Target Class<T> target, @DelegatesTo(genericTypeIndex=0) Closure cl) {
          def obj = target.newInstance() 
          cl.delegate = obj
          cl.resolveStrategy = Closure.DELEGATE_FIRST
          cl.call()
          obj 
         }
        }
        
        @groovy.transform.CompileStatic
        class Main {
         void run() {
          def builder = new Builder()
          def car = builder.configure(Car) {
            setBrand('BMW') // have to use method syntax (known issue)
          }
          assert car.brand == "BMW" // [Static type checking] - No such property: brand for class: java.lang.Object
         }
        }
        
        new Main().run()
        
        Show
        Peter Niederwieser added a comment - After double-checking, above example does work in GroovyConsole 2.2.0-beta-1, which is great. However, it apparently stops working once configure and foo are declared in different classes. For example, the following isn't working: @groovy.transform.CompileStatic class Car { String brand } @groovy.transform.CompileStatic class Builder { def <T> T configure(@DelegatesTo.Target Class <T> target, @DelegatesTo(genericTypeIndex=0) Closure cl) { def obj = target.newInstance() cl.delegate = obj cl.resolveStrategy = Closure.DELEGATE_FIRST cl.call() obj } } @groovy.transform.CompileStatic class Main { void run() { def builder = new Builder() def car = builder.configure(Car) { setBrand('BMW') // have to use method syntax (known issue) } assert car.brand == "BMW" // [Static type checking] - No such property: brand for class: java.lang. Object } } new Main().run()
        Hide
        Peter Niederwieser added a comment -

        Actually, property syntax does work here, and the delegate type can be inferred as well. Only the return type can't be inferred. Inserting a cast (assert ((Car) car).brand == "BMW") solves the problem.

        Show
        Peter Niederwieser added a comment - Actually, property syntax does work here, and the delegate type can be inferred as well. Only the return type can't be inferred. Inserting a cast ( assert ((Car) car).brand == "BMW" ) solves the problem.

          People

          • Assignee:
            CÚdric Champeau
            Reporter:
            CÚdric Champeau
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: