1

This never completes:

Completable.complete()
        .andThen{ Completable.complete() }
        .test()
        .assertComplete()

This does complete:

Completable.complete()
        .andThen(Completable.complete())
        .test()
        .assertComplete()

According to Jake Wharton:

"You want andThen(Completable.complete()). Note the use of parenthesis and not curly braces. The latter creates a lambda that doesn't call its emitter."

Reference: https://github.com/ReactiveX/RxJava/issues/5551

Can anyone explain this in more detail? I thought I understood lambda's but this has really thrown me.

s1m0nw1
  • 76,759
  • 17
  • 167
  • 196
Thomas Cook
  • 4,371
  • 2
  • 25
  • 42

2 Answers2

3

With the curly braces, you're using SAM conversion and defining an anonymous CompletableSource instance by describing its single method inside the lambda.

This is the same as doing the following:

Completable.complete()
        .andThen(object: CompletableSource {
            override fun subscribe(cs: CompletableObserver) {
                Completable.complete()
            }
        })
        .test()
        .assertComplete()

As you can see, inside this CompletableSource you're doing nothing but creating a Completable instance and throwing away its result. For the chain to continue, you'd have to call methods on the CompleteableObserver that you've received as a parameter (for example, you could call onNext() and onComplete() on it).


Although it's almost the same syntax, here's the Java version, in case it helps you understand things:

Completable.complete()
        .andThen(new CompletableSource() {
            @Override
            public void subscribe(CompletableObserver cs) {
                Completable.complete();
            }
        })
        .test()
        .assertComplete();
zsmb13
  • 85,752
  • 11
  • 221
  • 226
  • 1
    Great great explanation, I must have been very tired, this makes complete sense. – Thomas Cook Jan 30 '18 at 19:02
  • 1
    It's one of those gotchas that everyone using Kotlin and Rx are bound to spend a couple hours debugging, unfortunately. It happens with other Rx classes and operators too. – zsmb13 Jan 30 '18 at 19:04
  • Brain melt :D it's the same thing that's hurting my brain trying to learn Haskell – Thomas Cook Jan 30 '18 at 19:05
1
  1. The valid example in parentheses works as follows:

    Completable.complete() is executed and then passed as an argument to andThen.

  2. The invalid one does simply pass a lambda in curly braces as an argument to andThen, which becomes an implementation (thanks to SAM Conversion) of CompletableSource. It never gets executed. The following shows what you do:

    val compl = CompletableSource { Completable.complete() }
    Completable.complete()
        .andThen (compl)
        .test()
        .assertComplete()
        .assertComplete()
    
s1m0nw1
  • 76,759
  • 17
  • 167
  • 196