Home > Mobile >  Combining funtions with different types
Combining funtions with different types

Time:03-26

I am writing a method that is executing a variadic list of lambdas on an argument:

public class Main {
    static public<T, R> R convertBy(T data, Function... f) {
        Function composer = Function.identity();
        for (var fi: f ) {
            composer = composer.andThen(fi);
        }

        return (R)composer.apply(data);
    }

     public static void main(String[] args) {
        Function<String, String> l1 = x -> x.toLowerCase(Locale.ROOT);
        Function<String, Integer> l2 = String::length;

        Integer ret = convertBy("Lorem ipsum", l1, l2);
      }
}

Is there a way to use templates and not raw Functions? By that I mean some kind of way to express this transformation using templates: T -> ... -> R. Or at least get rid of the casting to R in return.

CodePudding user response:

You can't do this with a variadic argument, because you then need all of the functions to be of the same type: that means that all of the functions have to have the same input and output type, in order that the output of one call can be passed as the input to the next.

In other words, R must be equal to T.

static public<T> T convertBy(T data, Function<T, T>... fs) { ... }

You can pretend to support variadic arguments by providing a number of overloads, for the 1, 2, 3, ... N cases:

static public<T0, T1> T1 convertBy(T0 data, Function<T0, T1> f0) { ... }
static public<T0, T1, T2> T2 convertBy(T0 data, Function<T0, T1> f0, Function<T1, T2> f1) { ... }
static public<T0, T1, T2, T3> T3 convertBy(T0 data, Function<T0, T1> f0, Function<T1, T2> f1, Function<T2, T3> f2) { ... }

Which obviously involves a fair bit of code duplication. (There is prior art for this, for example in the List.of methods)

But other than that, there is no good way of expressing it in a type-safe way.

However, because these aren't actually variadic methods, you can't call them with an array of functions. Given that, it doesn't make much sense to have all of these overloads, because you can just use andThen to chain the functions; and then just use the apply method:

T result = f0.andThen(f1).andThen(f2).apply(data);
  • Related