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

Implicit closure coercion doesn't work for elements of array of functional objects

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 2.4.7
    • 4.0.4
    • Compiler

    Description

      Implicit closure coercion is described here - it assumes that the closures don't need to be casted to functional types and the generic types will be inferred by the compiler.

      Here is one contrived case that works from Java (this is not production code and is writen explicitly for illustration purposes):

      public class GroovyAccDemo {
          @SafeVarargs
          public static <T, R> Function<T, R> ensemble(Function<T, R>... hypotheses) {
              return t -> Arrays.stream(hypotheses)
                                .map(v -> v.apply(t))
                                .collect(Collectors.groupingBy(e -> e, Collectors.counting()))
                                .entrySet()
                                .stream()
                                .max(Comparator.comparingLong(Map.Entry::getValue))
                                .map(Map.Entry::getKey).orElseGet(() -> null);
          }
      
          public static void main(String[] args) {
              Function<Integer, Integer> foo = ensemble(
                      i -> i*i,
                      i -> i+i,
                      i -> i*i - (i+i)
              );
          }
      }
      

      Here the ensemble() method accepts a number of compatible functions and returns a single function that calls all hypotheses and returns the most popular result.

      The main method illustrates that we can use the ensemble() function with Java Lambdas without any explicit casts.

      If we try to do the same in Groovy, we'll get runtime error (or compile error if static compilation is enabled):

                  foo = GroovyAccDemo.<Integer, Integer> ensemble(
                          { i -> i * i },
                          { i -> i + i },
                          { i -> i * i - (i + i) }
                  );
      

      We can make it work by explicitly coercing the closures like this:

                  foo = GroovyAccDemo.ensemble(
                          { i -> i*i } as Function,
                          { i -> i+i } as Function,
                          { i -> i*i - (i+i ) } as Function
                  );
      

      This may seem as contrived use case, but it makes the use of certain API's more tedious from Groovy than from Java, which just feels wrong

      Attachments

        Issue Links

          Activity

            People

              emilles Eric Milles
              ddimitrov Dimitar Dimitrov
              Votes:
              1 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: