question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Decouple switching logic from switchMap operator and consistent naming

See original GitHub issue

We currently have a switchMap { ... } operator that is similar to the corresponding swithMap operator from Rx but from the standpoint of Kotlin coroutines looks like an amalgam of different operations that might need to be decoupled. The most basic operation seems to be this one, tentatively named as switchTransform:

fun <T, R> Flow<T>.switchTransform(transform: suspend FlowCollector<R>.(value: T) -> Unit): Flow<R>

It would be similar to Flow.transform but with a difference that transform waits for transformation to complete for each element while switchTransfrom would cancel the ongoing transformation on new incoming element and start it again.

Now, note that transform operator can be used to implement the host of basic operators:

filter(predicate) = transform { if (predicate(it)) emit(it) }
map(block) = transform { emit(block(it)) }
flattenConcat() = transform { emitAll(it) }
flatMapConcat(block) = map(block).flattenConcat() = transform  { emitAll(block(it)) } 
onEach(block) = transform { block(it); emit(it) }
collect(block) = transform { block(it) }.collect()

So, if we have a basic switchTransform operator, then it would be fitting to potentially have (at least reserve the names) the whole family of switchXxx operators that are similar to the above above when you replace transform with switchTransform in their implementations.

Moreover, there is a use case (see #1269) for the collectLatest terminal operator that should be called switchCollect under this proposed nomenclature, because:

swithCollect(block) = switchTransform { block(it) }.collect()

However, this switchXxx nomenclature has the following problem.

Under the proposed switchXxx nomenclature switchMap operator shall have the same signature as map (operates on Flow<T>) and should be equivalent to switchTransform { emit(block(it)) }. But we already have experimental switchMap operator that operates on Flow<Flow<T>> and does switchTransform { emitAll(block(it)) } which under the new nomenclature should have been called switchFlattenMapConcat. It is not clear how to proceed.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:3
  • Comments:9 (8 by maintainers)

github_iconTop GitHub Comments

3reactions
elizarovcommented, Jul 16, 2019

@zach-klippenstein Terrific. This (tentative) cancelOnNext is the core primitive. So we can have:

flattenLatest() = cancelOnNext().flattenConcat()
// Note: block in swtichMap is cancelled on emission too, so this is the correct impl: 
flatMapLatest(block) = cancelOnNext().flatMapConcat(block)
collectLatest(block) = cancelOnNext().collect(block)

The trick is how to name it. Note, that we don’t have the concept of OnNext. On the other hand, it is quite a basic primitive and it looks somewhat similar to conflate:

  • conflate adapts fast emitter to slow collector by skipping emitted values.
  • cancelOnNext adapts fast emitter to slow collector by cancelling collector.
2reactions
elizarovcommented, Jul 16, 2019

Ok. So here is a take on the xxxLatest nomenclature. We can have transformLatest that cancels ongoing transformation and the following operators that are potentially derived from it:

mapLatest(block) = transformLatest { emit(block(it)) }
flattenLatest() = transformLatest { emitAll(it) } 
flatMapLatest(block) = map(block).flattenLatest() = transformLatest  { emitAll(block(it)) } 
collectLatest(block) = transformLatest { block(it) }.collect()

This would also mean that we deprecate switchMap and rename it to flatMapLatest.

This nomenclature produces the following distinctly named variants of flatMap operator with different merging strategies:

  • flatMapConcat/flattenConcat – concatenates all flows.
  • flatMapLatest/flattenLatest – cancels ongoing flow as soon as the new one appears.
  • flatMapMerge/flattenMerge – concurrently run flows and merge their results.

Indeed, I like the suffix nomenclature more. I don’t like introducing a strategy enum, though. It only makes subsequent dead-code elimination in Android via R8, in Kotiln/JS, and in Kotlin/Native harder.

P.S. There is might be some confusion with combineLatest operator that also ends with latest suffix but is otherwise completely unrelated to the abovexxxLatest family. Having thought about it a bit I don’t immediately see it as a big issue, even though it still bugs me a little.

Read more comments on GitHub >

github_iconTop Results From Across the Web

RxJs SwitchMap Operator: How Does It Work?
Let's now learn why the term switch is used to name the switchMap operator, by breaking down this output step-by-step: just like in...
Read more >
RxJS best practices in Angular - Blog - Brecht Billiet
Clean code practices. Consistent code indentation and formatting can improve the readability of complex streams: Align operators below each ...
Read more >
Switching to the Most Recent Observable with switchMap
In this guide, we'll be learning about the switchMap operator. The switchMap operator maps each value to an observable, then it flattens all ......
Read more >
Redux-Observable will solve your state problems. - ITNEXT
Now we're seeing a new operator: switchMap . This, and a few others like it, are by-far the most-important operators since they allow...
Read more >
Change log for kotlinx.coroutines
Operators for UI programming are reworked for the sake of consistency, naming scheme for operator overloads is introduced: combineLatest is deprecated in ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found