Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add debounce selector #2314

Closed
wants to merge 3 commits into from
Closed

Conversation

mkano9
Copy link
Contributor

@mkano9 mkano9 commented Oct 18, 2020

Adding support for debounce selector to allow changing debounce time based on the latest emitted value.

Resolves #1216.

Reopening my PR as I accidentally messed up my branch.

@mkano9 mkano9 mentioned this pull request Oct 18, 2020
@mkano9
Copy link
Contributor Author

mkano9 commented Oct 18, 2020

@elizarov I opened this as a new PR as I messed up my branch in #2148.

I made the changes requested and it's ready for another review. Thanks in advance.

@@ -129,7 +151,98 @@ public fun <T> Flow<T>.debounce(timeoutMillis: Long): Flow<T> {
*/
@ExperimentalTime
@FlowPreview
public fun <T> Flow<T>.debounce(timeout: Duration): Flow<T> = debounce(timeout.toDelayMillis())
public fun <T> Flow<T>.debounceWithDuration(timeout: Duration): Flow<T> = debounce(timeout.toDelayMillis())
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not ideal that I am renaming this method from Flow<T>.debounce(timeout: Duration): Flow<T>.

The selector variation method name Flow<T>.debounce(timeout: (T) -> Duration): Flow<T> below was conflicting with Flow<T>.debounce(timeoutMillis: (T) -> Long): Flow<T>. I could just rename only the duration selector variation to e.g. Flow<T>.debounceWithDurationSelector(timeout: (T) -> Duration): Flow<T>, but I felt this would be a better grouping to keep the word duration in the method names for both instead of just one of them.

Please let me know if renaming an existing method concerns.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The right way to do it is this:

  • Keep the Kotlin name debounce
  • Add @JvmName("debounceDuration") to avoid platform declaration clash (we don't use With or other prepositions in these kind of names).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JvmName does not seem to work when a function argument is used. I see the issue mentioned in https://youtrack.jetbrains.com/issue/KT-22119. I pushed with debounceDuration(...).

while (lastValue !== DONE) {
select<Unit> {
// Give a chance to consume lastValue first before onReceiveOrNull receives a new value
lastValue?.let { value ->
Copy link
Contributor Author

@mkano9 mkano9 Oct 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reversed the order of values.onReceiveOrNull and lastValue?.let because when the flow emits "A", "B" at once with 0 timeout like the testZeroDebounceTimeSelector test, values.onReceiveOrNull kept picking it up first and get selected by select<Unit>; therefore, skipping the first value "A".

Copy link
Contributor

@elizarov elizarov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also needs to fix the name of debounchWithDelay (see comment) and update apiDump.


if (timeoutMillis == 0L) {
lastValue = null
runBlocking {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of runBlocking/launch here? It should be just downstream.emit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get the Suspension functions can be called only within coroutine body error. Any suggestions? I used runBlocking to make sure it gets executed before moving on.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's exactly what emit is doing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I meant to say that the select {} block does not let me call a suspend function downstream.emit(unboxedValue).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should move this code outside of select {} block, that is, you should check conditions and emit if needed first, then do select.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I pushed a fix for this.

@mkano9
Copy link
Contributor Author

mkano9 commented Oct 25, 2020

@elizarov It's ready for another review.

@elizarov elizarov mentioned this pull request Oct 26, 2020
@elizarov
Copy link
Contributor

I've restored binary compatibility with the previous version, cleaned up implementation a bit, and reopened it as #2336 (see the last commit for the proper combination of annotation)

@elizarov elizarov closed this Oct 26, 2020
@mkano9
Copy link
Contributor Author

mkano9 commented Oct 26, 2020

@elizarov Thank you for the reviews and for merging it! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants