So I am trying to write an internal DSL and having a hard time to get generics work the way I want. I know I can write one method call like
collectingAndThen(toSet(), Set::size);
but I want to write
toSet().andThen(Set::size)
which works OK here where I am passing the result into a method parameter, like so
var grouped = collect(groupingBy(i->i % 3, toSet().andThen(Set::size)), that);
but here where I try to return it
public static <X> Collector<X,Set<X>,Integer> countDistinct() { // return collectingAndThen(toSet(), Set::size); return Collectors.<X>toSet().andThen(Set::size); }
I have to write
Collectors.<X>toSet().andThen(Set::size);
to tell the compiler what the type parameter is. In my mind it should be able to figure it out, but the compiler tells me
incompatible types: no instance(s) of type variable(s) FinalResult exist so that com.ontology2.pidove.checked.Collector<java.lang.Object,java.util.Set<java.lang.Object>,FinalResult> conforms to com.ontology2.pidove.checked.Collector<X,java.util.Set<X>,java.lang.Integer>
Here are the definitions:
public static <X> SimpleCollector<X, Set<X>> toSet() { return toCollection(HashSet::new); } public record SimpleCollector<Input, Result> ( Supplier<Result> supplier, BiConsumer<Input, Result> accumulator ) implements AnyCollector<Input, Result> { public <FinalResult> Collector<Input,Result,FinalResult> andThen(Function<Result,FinalResult> finisher) { return Collector.of(supplier(), accumulator(), finisher); } }
if I don't put in the <X>. I like the way Function.andThen() works and I'd like to make my andThen() work the same way. Am I missing something or I am butting my head against type erasure or both?
Can I make this work or should I just settle for writing static functions that always get applied on the left?