Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin constructor reference with generics

I have this code in (Rx)Java:

Observable.fromArray(1, 2, 3)
    .flatMap(this::intToBooleanObservable, Pair::new)
    .....

I would expect to corresponding Kotlin code to look like:

Observable.fromArray(1, 2, 3)
    .flatMap(::intToBooleanObservable, ::Pair)
    .....

However the compiler cannot infer the generic type of Pair, so the best I can do right now is:

.flatMap(::intToBooleanObservable, { a, b -> a to b })

Which isn't as concise as I would like it to be.

Is there a way to achieve this without declaring the variables a and b?

like image 502
Stav Raviv Avatar asked Jun 08 '17 01:06

Stav Raviv


1 Answers

Same trouble here. A few other workarounds (in the order I used them), you may like one of those.

1) Writing your own operator:

fun <T, U> Single<T>.flatMapPair(func: (T) -> Single<U>) : Single<Pair<T, U>> {
    return this.flatMap { t -> func.invoke(t).map { u -> t to u } }
}

2) Move the wrapping to the conditional Observable (here intToBooleanObservable), returning the result as a Pair or a more explicit and custom type (sealed class with 2 childs, like Success and Failure). This enable more explicit code :

 when(it) {
   is Success -> ...
   is Failure -> ...
}

3) Depending on intToBooleanObservable result you have now 2 different scenario (I imagine). Usually one is a sort of failure/denial, quick to resolve. For this matter write a filter with side effect where the predicate is an Observable, thus avoiding the problem :

fun <T> Observable<T>.filterSingle(predicate: (T) -> Single<Boolean>, rejectionFunction: (T) -> Unit): Observable<T> = ... //filter with the given predicate, and call rejectionFunction if item doesn't pass

4) The last method work only with boolean result. What if I am interested by the reason behind failure/refusal to give a meaningful message ? For the sake of homogeneous code, I dropped this operator. Inspired by other functionals languages, I defined a Either type and defined generic Either+RxJava operators; mapRight, flatMapRight and more important dropLeft. dropLeft is like a generalization of filterSingle.

inline fun <L, R> Observable<Either<L, R>>.dropLeft(crossinline sideEffect: (L) -> Unit): Observable<R> = this.lift { downObserver ->
    object: Observer<Either<L, R>> {
        override fun onError(throwable: Throwable?) = downObserver.onError(throwable)

        override fun onSubscribe(disposable: Disposable?) = downObserver.onSubscribe(disposable)

        override fun onComplete() = downObserver.onComplete()

        override fun onNext(either: Either<L, R>) = when (either) {
            is Right -> downObserver.onNext(either.value)
            is Left -> sideEffect(either.value)
        }
    }
}

Hope it could help.

like image 65
Geoffrey Marizy Avatar answered Dec 16 '22 22:12

Geoffrey Marizy