Never break the chain: use Kotlin's extension functions
Years ago I wrote about properly reusing operators in RxJava. In summary, the wrong way to reuse operators is to wrap the Observable
(which is bad because it breaks the fluency of the code), whereas the right way is to use compose()
(which is good because it maintains fluency):
// BAD
fun <T> applyOperators(obs: Observable<T>): Observable<T> { ... }
applyOperators(Observable.just(source))
// GOOD
fun <T> applyOperators(): ObservableTransformer<T, T> { ... }
Observable.just(source).compose(applyOperators())
Since that post, Kotlin has become a major JVM language. I use it all the time and prefer it to Java.
Kotlin has extension functions, which allows you to safely "add" a function to an existing type. One consequence of extension functions is that compose()
is entirely unnecessary when using Kotlin. If you think about it, compose()
is basically just a way to add extensions for just RxJava; but in Kotlin, you can easily add extensions to anything!
Here's the above example with compose()
replaced by an extension function:
fun <T> Observable<T>.applyOperators(): Observable<T> { ... }
Observable.just(source).applyOperators()
If you want Java interop, then compose()
is still required. But if you're operating in Kotlin land, skip it! Extensions are a core language feature and more succinct than compose()
.
On top of that, you can apply the lesson we learned from compose()
anywhere else in your codebase. Before Kotlin, you were often forced to create wrapper functions; now you can create fluent interfaces wherever you want, which often results in easier-to-understand code.