2

Last few days I am trying to migrate my project from RxJava 1.x.x to RxJava 2.x.x. I have this simple method. Everything is OK if I use the Observables from rxjava 1.x.x (rx.Observable). However, when I replaced it with "new" observables (io.reactivex.Observable, I get an error saying : "Type inference failed. Please specify it explicitly"

fun <T1, T2, T3, R> combineLatestValue3Nullable(observable1: Observable<T1?>, observable2: Observable<T2?>, observable3: Observable<T3?>, merge: (T1, T2, T3?) -> R): Observable<R?> {
    return Observable.combineLatest(observable1, observable2, observable3) {
        value1, value2, value3 ->
        var result: R? = null
        if (value1 != null && value2 != null) {
            result = merge(value1, value2, value3)
        }
        result
    }
}

Do you have any idea what I do wrong? Can you please explain what exactly cause this error in RxJava 2?

Somebody (here) had a problem very similar to this. However, they are using BiFuntion in their solution which accepts two arguments and creates a result. As you can see I use more arguments (3) so I can't use Bifunction here.

Tom Wayne
  • 1,288
  • 1
  • 12
  • 31
  • Possible duplicate of [Observable.combineLatest type inference in kotlin](https://stackoverflow.com/questions/42725749/observable-combinelatest-type-inference-in-kotlin) – zsmb13 Jul 15 '17 at 09:07
  • No, I wouldn't say that this is a duplicate question. I saw their solution and it doesn't work for me. They are using BiFuntion which accepts two arguments and creates a result. As you can see I use more arguments (3) so I can't use Bifunction here. – Tom Wayne Jul 15 '17 at 14:06
  • 1
    You're right, this is a different question indeed. If it was only more arguments, I think you could just use `Function3` the same way as the `BiFunction` example, but you have generics as well to complicate things. I think this will only work if you write out the full `object` syntax to create a `Function3`, with explicit types. – zsmb13 Jul 15 '17 at 18:18
  • 1
    You can't use nulls (and nullable types) in RxJava 2. That function can never be called because Observables of nullable types don't exist. If you absolutely have to recognize absence of a value, use Optional. – Eugen Pechanec Jul 15 '17 at 18:22
  • 1
    @PepaHruška Interesting. I answer the question just now. please see [my answer](https://stackoverflow.com/questions/45120698/rewrite-java-code-using-method-reference-to-kotlin). if you have some doubts add a comment below my answer. – holi-java Jul 15 '17 at 19:17
  • @zsmb13 I didn't know about Function3, Function4 etc. I just put the Function3 there and it worked. I just had to remove nullable return type of this method. Thanks – Tom Wayne Jul 16 '17 at 13:10
  • @EugenPechanec Thanks for advice. I didn't know about Optional class - it may be handy. – Tom Wayne Jul 16 '17 at 13:15
  • @holi-java I saw your answer. Thanks for explaining this so thoroughly. It 's interesting – Tom Wayne Jul 16 '17 at 13:15
  • @PepaHruška Not at all. – holi-java Jul 16 '17 at 13:17

3 Answers3

2

In the end I found a solution based on given advice above. The first thing which should be mentioned is the fact that we shouldn't return nullable Observable at all. If we need to check values passed to combineLatest we should do it before instead of checking it inside combineLatest.

When we remove nullability the method looks like this:

fun <T1, T2, T3, R> combineLatest(observable1: Observable<T1>, observable2: Observable<T2>, observable3: Observable<T3>, merge: (T1, T2, T3) -> R): Observable<R> {
    return Observable.combineLatest(observable1, observable2, observable3, Function3 {
        value1, value2, value3 ->
        merge(value1, value2, value3)
    })
}

The only additional thing which I had to change is to replace lambda with Function3 - it solves the problem of type inference.

If you have just two values for combineLatest you can use BiFuntion instead of Function3.

If you need to pas for example 6 variables to combineLatest you can use Function6 etc.

See all the variants below:

fun <T1, T2, R> combineLatest(observable1: Observable<T1>, observable2: Observable<T2>, merge: (T1, T2) -> R): Observable<R> {
    return Observable.combineLatest(observable1, observable2, BiFunction {
        value1, value2 ->
        merge(value1, value2)
    })
}

fun <T1, T2, T3, R> combineLatest(observable1: Observable<T1>, observable2: Observable<T2>, observable3: Observable<T3>, merge: (T1, T2, T3) -> R): Observable<R> {
    return Observable.combineLatest(observable1, observable2, observable3, Function3 {
        value1, value2, value3 ->
        merge(value1, value2, value3)
    })
}

fun <T1, T2, T3, T4, R> combineLatest(observable1: Observable<T1>, observable2: Observable<T2>, observable3: Observable<T3>, observable4: Observable<T4>, merge: (T1, T2, T3, T4) -> R): Observable<R> {
    return Observable.combineLatest(observable1, observable2, observable3, observable4, Function4 {
        value1, value2, value3, value4 ->
        merge(value1, value2, value3, value4)
    })
}

fun <T1, T2, T3, T4, T5, R> combineLatest(observable1: Observable<T1>, observable2: Observable<T2>, observable3: Observable<T3>, observable4: Observable<T4>, observable5: Observable<T5>, merge: (T1, T2, T3, T4, T5) -> R): Observable<R> {

    return Observable.combineLatest(observable1, observable2, observable3, observable4, observable5, Function5 {
        value1, value2, value3, value4, value5 ->
        merge(value1, value2, value3, value4, value5)
    })
}

fun <T1, T2, T3, T4, T5, T6, R> combineLatest(observable1: Observable<T1>, observable2: Observable<T2>, observable3: Observable<T3>, observable4: Observable<T4>, observable5: Observable<T5>, observable6: Observable<T6>, merge: (T1, T2, T3, T4, T5, T6) -> R): Observable<R> {
    return Observable.combineLatest(observable1, observable2, observable3, observable4, observable5, observable6, Function6 {
        value1, value2, value3, value4, value5, value6 ->
        merge(value1, value2, value3, value4, value5, value6)
    })
}

fun <T1, T2, T3, T4, T5, T6, T7, R> combineLatest(observable1: Observable<T1>, observable2: Observable<T2>, observable3: Observable<T3>, observable4: Observable<T4>, observable5: Observable<T5>, observable6: Observable<T6>, observable7: Observable<T7>, merge: (T1, T2, T3, T4, T5, T6, T7) -> R): Observable<R> {
    return Observable.combineLatest(observable1, observable2, observable3, observable4, observable5, observable6, observable7, Function7 {
        value1, value2, value3, value4, value5, value6, value7 ->
        merge(value1, value2, value3, value4, value5, value6, value7)
    })
}

fun <T1, T2, T3, T4, T5, T6, T7, T8, R> combineLatest(observable1: Observable<T1>, observable2: Observable<T2>, observable3: Observable<T3>, observable4: Observable<T4>, observable5: Observable<T5>, observable6: Observable<T6>, observable7: Observable<T7>, observable8: Observable<T8>, merge: (T1, T2, T3, T4, T5, T6, T7, T8) -> R): Observable<R> {
    return Observable.combineLatest(observable1, observable2, observable3, observable4, observable5, observable6, observable7, observable8, Function8 {
        value1, value2, value3, value4, value5, value6, value7, value8 ->
        merge(value1, value2, value3, value4, value5, value6, value7, value8)
    })
}
Tom Wayne
  • 1,288
  • 1
  • 12
  • 31
1

Are you using RxKotlin? If not, I'd suggest giving that a try as it has SAM helpers for various methods, including combineLatest, which is one of the methods affected. See their docs for more info.

junglie85
  • 1,243
  • 10
  • 30
1

I had the same problem. Then I saw that Kotlin has a function with the same name, and it is used by default. So I just imported the RxJava function explicitly and this helped me get rid of the error:

import io.reactivex.functions.Function3
Alektas
  • 556
  • 4
  • 11