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
?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With