Search code examples
javagenericsrx-javakotlinrx-kotlin

Expressing "super" generics in Kotlin functional types?


I'm trying to port an RxJava library and leverage extension functions in Kotlin.

fun <T,R: MutableCollection<T>> Observable<T>.collectWhile(factory: (() -> R), condition: (R,T) -> Boolean) =
        compose(Transformers.collectWhile(factory,condition))

The Transformers.collectWhile() is written in Java and has this signature:

public static <T, R extends Collection<T>> Transformer<T, R> collectWhile(final Func0<R> factory,
            final Action2<? super R, ? super T> collect)

However, I am getting an issue with mapping the collect argument and I'm not good at generics. How do I express super with a functional type?

UPDATE

Stupid mistake on my part. I should not have been posting on SO late at night.

I was actually targeting this

public static <T, R extends Iterable<?>> Transformer<T, R> collectWhile(final Func0<R> factory,
        final Action2<? super R, ? super T> collect, final Func2<? super R, ? super T, Boolean> condition)

And this is what I should have done.

fun <T,R: MutableCollection<T>> Observable<T>.collectWhile(factory: (() -> R), action: (R,T) -> Unit, condition: (R,T) -> Boolean) =
    compose(Transformers.collectWhile(factory,action,condition))

Solution

  • Java wildcard type ? super T corresponds to in T use-site type projection in Kotlin, so the corresponding type of collect parameter would be Action2<in R, in T>.

    That type is roughly equivalent (or more specifically is eligible for SAM-conversion) to (R, T) -> Unit functional type in Kotlin, because (R, T) -> Unit is a synonym for type Function2<R, T, Unit> and the latter is equivalent to Function2<in R, in T, out Unit> due to the declaration-site variance of the Function2 type parameters.

    You cannot pass a function of type (R, T) -> Boolean as an argument to collect, where (R, T) -> Unit is expected.

    Either change the type of collect parameter, or the type of condition parameter`.