Subject + operators should return another Subject, not an Observable #7547
dariomannu
started this conversation in
Report issues other than bug
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
In either form:
the above should return a Subject, not an Observable.
I feel strongly about this. It's basic monadic laws we should really not start to break now: given a monad of type T, when you bind it (=you run any operator in this case), it must return a monad of the same type.
So Promise->another Promise, Subject->another Subject, Behavior->another Behavior, Observable->another Observable.
I understand that
Subject.pipe()
was always documented as returning another Observable, not a Subject, yet it did in fact expose the Subject interface. Also, some people raised concerns about this hidden mismatch.I understand this is controversial and that a number of (mostly Angular, from what I've seen) developers expressed worries about unnecessarily or involuntarily exposing write access to streams only meant to be read, so they have to call toObservable many times.
However, enforcing trusted/untrusted boundaries in code is not a problem that should be solved by the implementation of Subject/BehaviorSubject, I'd argue.
I understand there are people like Erik Meijer himself who once referred to Subject as the mutable state of streams because its openness to imperative abuse, but it's important to distinguish between genuine abuse vs other genuinely valid use cases:
Sometimes 1 and 2 above are simple escape hatches for situations in which it's hard to define the streams in proper declarative/functional style, but I found that to be a limitation imposed by imperative frameworks and APIs only conceived for imperative programming, rather than the Subject being an anti-pattern by itself.
There are still genuine and valid use cases for Subject to exist and be passed around with its Observer interface exposed, like in example 3 above.
Rx8 is breaking this?
I noticed in Rx8 if you do
rx(new Subject, ...ops)
it no longer returns a Subject but a plain Observable, so it's a top breaking change from 7.x nobody talked about. Was that intentional? Can we have some comments on that, please?I feel it's really important to be aware of this and revert to the previous behavior, rather than silently make such a big change.
Perhaps alternative, additional constructs may be conceived, so that we can still have a
Subect.pipe()
explicitly returning a Subject and a separate (whatever its name or form)ReadOnlySubject.pipe()
orSubject.readOnlyPipe()
that only returns an Observable. For the new syntax even something like (a good name to be found yet)readonly_rx(Subject, ...ops)
.However,
rx(Subject, ...ops)
I think should still return an untrimmed Subject.At least this could be consistent with past behaviour.
Beta Was this translation helpful? Give feedback.
All reactions