Search code examples
refactoringrx-java2

Identical Observable inside a switchMap


Please take a look at the following code:

class FooImplTest {

    @Test
    fun sample1() {
        val booleanSubject = BehaviorSubject.create<Boolean>()
        val intSubject = BehaviorSubject.create<Int>()
        val stringSubject = BehaviorSubject.create<String>()

        val combineSecondAndThird = Observable.combineLatest(intSubject, stringSubject,
            { t1, t2 -> Pair(t1, t2) })

        intSubject.onNext(1)
        stringSubject.onNext("my str")

        booleanSubject.onNext(true)

        val o1 = combineSecondAndThird
            .switchMap { pair ->
                val i = pair.first
                val s = pair.second

                booleanSubject.switchMap {
                    intSubject.map { secondVal2 -> Triple(i,
                        "$s:$it", secondVal2) }
                }
            }
            .test()
            .assertValue(Triple( 1, "my str:true", 1))

        intSubject.onNext(3)

        o1.assertValueAt(1, Triple( 3, "my str:true", 3))
            .dispose()
    }

}

I think no need to subscribe to intSubject inside booleanSubject.switchMap:

booleanSubject.map { Triple(i,"$s:$it", i) }

I just wonder if there are any edge cases where the original code will yield a result different from the simplified code.


Solution

  • Why would you not just compose all three subjects into combineLatest, just like following example?

    @Test
    fun sample1() {
        val booleanSubject = BehaviorSubject.create<Boolean>()
        val intSubject = BehaviorSubject.create<Int>()
        val stringSubject = BehaviorSubject.create<String>()
    
        val combined = Observable.combineLatest(
            intSubject,
            stringSubject,
            booleanSubject,
            Function3<Int, String, Boolean, Triple<Int, String, Int>> { i, s, b ->
                Triple(i, "$s:$b", i)
            })
    
        intSubject.onNext(1)
        stringSubject.onNext("my str")
    
        booleanSubject.onNext(true)
    
        val test = combined
            .test()
            .assertValue(Triple(1, "my str:true", 1))
    
        intSubject.onNext(3)
    
        test.assertValueAt(1, Triple(3, "my str:true", 3))
            .dispose()
    }
    

    The test passes, as before. When all values are emitted synchronous, it should not matter, becaues combineSecondAndThird#switchMap should always be called first.