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

Fix groupBy() to use lift() #1128

Closed
wants to merge 3 commits into from
Closed

Conversation

staltz
Copy link
Member

@staltz staltz commented Jan 4, 2016

Addresses bug #1085.

  • Adds tests on Observable to verify that basic lift() features work.
  • Adds tests on groupBy to assert it does not break lift() features.
  • Fixes groupBy to use lift().

BREAKING CHANGES:
groupBy() now unsubscribes all inner Observables when the outer
Observable is unsubscribed. This diverges from the behavior in RxJS 4,
where inner Observables continue even if the outer is unsubscribed.

RxJS 4 explicitly supports the "inners continue when outer is unsubscribed", see this test. @Blesh @trxcllnt @mattpodwysocki what do you think about the breaking change I'm proposing? It seems odd to me why shouldn't we dispose of inners. I don't know if and why there is anyone depending on this behavior.

@mattpodwysocki
Copy link
Collaborator

@staltz I'm not a fan of this breaking change as the inners should be independent of the outers which makes them more reliable as you pass the inners around for streaming purposes and to be weirdly affected by something upstream. It's best to be kept as it was in RxJS v4 cc @headinthebox

@benlesh
Copy link
Member

benlesh commented Jan 7, 2016

@mattpodwysocki I can see what you're talking about, but I'm having a hard time coming up with example code that would do this without doing something obviously strange.

@benlesh
Copy link
Member

benlesh commented Jan 7, 2016

Also, why wouldn't we terminate those groups if they couldn't possibly produce another value because the source was terminated? It sounds more like a bug than a feature, TBH.

@benlesh
Copy link
Member

benlesh commented Jan 7, 2016

Perhaps a middle-ground would be to have the inner streams error when the upstream is unsubscribed with a custom error like UnsubscribedSourceError. Then if the desired behavior is for the stream to continue on, you could handle that specific error with catch and return an Observable.never().

@benlesh
Copy link
Member

benlesh commented Jan 13, 2016

@staltz ... this needs to be rebased before I can merge it.

@staltz
Copy link
Member Author

staltz commented Jan 13, 2016

Rebased! :)

@mattpodwysocki
Copy link
Collaborator

@staltz @Blesh I still have concerns about the independence of the inner versus outer subscriptions. I wouldn't merge until we come up to some agreement on this because it diverges from all other Rx implementations.

@staltz
Copy link
Member Author

staltz commented Jan 13, 2016

@mattpodwysocki window also behaves like this (inners are unsubscribed when the outer is unsubscribed). Why is groupBy different? Who actually needs the use case you are portraying?

@trxcllnt
Copy link
Member

@staltz GroupedObservable is similar to ConnectableObservable, since they both front for a shared Subject. Multiple people can connect to the same ConnectableObservable without interfering with each other. The same should be true for GroupedObservable.

I know that's how GroupedObservable works in this PR, but this leads me to my next point:

Once groupBy has emitted a GroupedObservable, that GroupedObservable has left the safety and comfort of the groupBy operator. Disposing the GroupBySubscriber shouldn't dispose inner GroupedObservables, because they might have subscription side-effects that groupBy doesn't know about.

For example, if you multicast a GroupedObservable with a ReplaySubject, unsubscribing from the GroupBySubscriber would call unsubscribe on the ReplaySubject, which would be incorrect.

@mattpodwysocki
Copy link
Collaborator

@trxcllnt well said, and exactly my concerns that I had, which is why inner independence was necessary.

@staltz
Copy link
Member Author

staltz commented Jan 14, 2016

Does that apply also to window?

RxJS 4 https://jsbin.com/pukeni/edit?js,console
RxJS 5 https://jsbin.com/sajuwu/edit?js,console

@mattpodwysocki
Copy link
Collaborator

@staltz no, this not independent of the outer subscription, upon disposal, it still ensures that the window is eventually emptied and then it stops.

@staltz staltz force-pushed the groupBy-lift branch 2 times, most recently from 0ef4864 to f0ad32a Compare January 18, 2016 13:15
@staltz
Copy link
Member Author

staltz commented Jan 18, 2016

@Blesh @mattpodwysocki this PR is now safe to merge, I re-implemented the solution to keep it backwards-compatible as Matt wishes. We can/could postpone the discussion on subscription independence. The priority was to get groupBy working with lift().

@mattpodwysocki
Copy link
Collaborator

@staltz To be fair, it was both @trxcllnt and myself who wanted to keep independence. Also, I don't see the tests associated with this to check for the independence of the inner from the outer such as these from groupBy and groupByUntil

@staltz
Copy link
Member Author

staltz commented Jan 18, 2016

Also, I don't see the tests associated with this to check for the independence of the inner from the outer such as these from

The tests were not added in this PR because they are already there, I had ported them from RxJS 4 to this repo long ago.

@benlesh
Copy link
Member

benlesh commented Jan 18, 2016

LGTM.

@benlesh benlesh added PR: lgtm and removed blocked labels Jan 18, 2016
@mattpodwysocki
Copy link
Collaborator

@staltz ah, sorry about that. LGTM then!

@@ -211,7 +211,7 @@ export class Observable<T> implements CoreOperators<T> {
projectResult?: (x: T, y: any, ix: number, iy: number) => R,
concurrent?: number) => Observable<R>;
flatMapTo: <R>(observable: Observable<any>, projectResult?: (x: T, y: any, ix: number, iy: number) => R, concurrent?: number) => Observable<R>;
groupBy: <K, R>(keySelector: (value: T) => string,
groupBy: <T, K, R>(keySelector: (value: T) => K,
Copy link
Member

Choose a reason for hiding this comment

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

do we need to add T as function generic parameter? expect T comes from generic type of Observable<T>.

Copy link
Member Author

Choose a reason for hiding this comment

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

I remember TS was complaining and this solved it, but I can re-check.

@staltz
Copy link
Member Author

staltz commented Jan 25, 2016

@kwonoj I updated the TS typing issue that you pointed out.

@kwonoj
Copy link
Member

kwonoj commented Jan 25, 2016

Thanks, change looks good to me too.

@benlesh
Copy link
Member

benlesh commented Jan 25, 2016

:) Sorry @staltz, can you rebase this one?

Add tests for Observable to verify that the most important codebase-wide features brought by the
lift architecture are satisfied.

Refers to discussion in ReactiveX#60.
Add test for groupBy() operator, to verify that it supports the composable lift architecture.

Test for issue ReactiveX#1085.
Fix bug ReactiveX#1085 in which groupBy was not using lift(). Using lift() is critical to support the
ubiquitous lift-based architecture in RxJS Next

Resolves ReactiveX#1085.
@staltz
Copy link
Member Author

staltz commented Jan 26, 2016

Alright, done

@benlesh
Copy link
Member

benlesh commented Jan 27, 2016

Merged as of 39ebae9... I basically took your whole PR as-is during rebase and reapplied my perf fixes.

Thanks @staltz! This was an important one.

@benlesh benlesh closed this Jan 27, 2016
@staltz staltz deleted the groupBy-lift branch January 27, 2016 20:13
@lock
Copy link

lock bot commented Jun 7, 2018

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Jun 7, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants