Replies: 3 comments 4 replies
-
Hmmmm, really good catch and really good question. Good mark for me that is should be covered in docs =) Lets move one by one:
disposable.dispose();
observable
| rpp::ops::subscribe_on(rpp::schedulers::new_thread{})
| rpp::ops::subscribe_on(rpp::schedulers::new_thread{})
| rpp::ops::subscribe_on(rpp::schedulers::new_thread{})
| rpp::ops::subscribe(disposable, [](int){});
^^^^^ really synthetic example, but: there obsefvable is pretty "heavy to subscribe" - it starts 3 threads for each subscriptions. In this case observer is JUST disposed for some reason before subscribe. Do we really need to move through all subscriptions chain to understand later that observer is not interested it that fact? I think no. It is pretty arguable decision, but main idea was: when observer reaches observable's subscribe - observer was interested in this action (at least, at the moment of begining of this call) One more thing about
Technically observer is SINGLE-THREADED object. All calls to observer HAVE to be done serially (it is why all observers are not copyable, but just movable by default). All rpp's operators handling it properly (not doing copies of observer and etc. If we need it, then access observer under lock).
Yeah, it is true, but we can't handle it somehow properly
rpp::source::just(rpp::schedulers::immediate{}, 1) | rpp::ops::subscribe([](int){}); could happens without ANY heap allocations (in contrast to rxcpp) So, in summary, it means that in most cases you behave like "hey, observable, take this observer and just call its methods, i don't care" (== default method without return value), while if you want to control observable-observer relationships, you need to call subscribe_with_disposable method or just use overloading accepting disposable + observer. |
Beta Was this translation helpful? Give feedback.
-
So, shorter summary:
|
Beta Was this translation helpful? Give feedback.
-
I am super unhappy that |
Beta Was this translation helpful? Give feedback.
-
I am curious how rpp solves the lifetime issues during subscription. I am referring to this code:
Do we really need the
is_disposed()
check? Does it save us from lifetime issues? Is it thread-safe?I may be wrong with what I say here, so please forgive the noise in that case.
AFAICS at the marked sequence point anything could happen to
observer
, especially adispose
call coming through anyway. Or a destructor kicking in, making the move not very successful.Generally speaking, IMHO any Reactive Extension C++ library should make it clear that lifetime issues are not its business, but the user's responsibility. So for me, it would be fine if
observable::subscribe
returned a (movable)subscription
object which I need to keep alive myself. The destructor ofsubscription
should unsubscribe its observers from the observable. I believe that emulating the lifetime management of Reactive Extension implementations in managed programming languages is a huge burden for rx C++ library authors.Saving CPU cycles like this:
I am pretty sure there are good arguments for your current design and I would like to hear your opinion on this.
Beta Was this translation helpful? Give feedback.
All reactions