3 ms·
Personally I'm a huge fan of Observables or (Singles which is a single item Observable). One of the most confusing things with Promises vs Observables or any s
by agentgt 10y ago
Personally I'm a huge fan of Observables or (Singles which is a single item Observable).
One of the most confusing things with Promises vs Observables or any sort of deferred value is whether it is "hot" or "cold".
Most deferred objects like Futures in Java and Promises in other languages are hot which basically means something is already running in the background.
There are many reasons why I prefer the cold model but mainly boils down to be more explicit, better composition, backpressure handling, and overall better predictability.
I wish articles talked about this a little more of hot vs cold.
- xenadu02 10y agoIndeed, this has been solved in Swift with ReactiveCocoa 3. SignalProducer<Value, Error> is a cold signal that must be started/observed to take effect. Signal<Value, Error> is hot. We have the lift operator that can transform any signal operator into a signal producer operator so you don't have to duplicate everything. If anyone is wondering: Cold signals don't do work until you ask for it; think starting a new network request. They don't send any values until someone starts them. Hot signals send values at their own leisure and often represent things out of your control, like button taps or receiving a push notification. They send values whether anyone is listening or not.
- inglor 10y agoObservables are actually terrible at backpressure as they're one of the most eager models around - once you have subscribed to an observable _it_ decides when to push and how much and you can't handle backpressure very well. Quoting Erik Meijer who invented Rx Observables: > My opinion about back pressure is that you either have a truly reactive system where the producer is fully in charge and the onus is on the consumer to keep up; or a truly interactive the consumer is fully in charge and the onus is on the producer to keep up. This is one of the cases where having different types of collections makes sense (just like we have different collections like lists, maps, sets, ... with different performance characteristics and different operations) You probably want an async iterator for that
- bad_user 10y agoYou've got certain misunderstandings there. Observables aren't eager, what you want to say is that they are push-based. But that doesn't mean they are terrible at back-pressure, in fact they can be better at back-pressure than any pull based model you can think of, because the communication is more efficient. Back-pressure is the scope of the http://reactive-streams.org http://reactive-streams.org protocol and I've also built a library inspired by Rx that has back-pressured observables, started before RxJava went this route as well: https://monix.io https://monix.io Funny enough back-pressure doesn't help with just "slow consumers". In Rx.NET flatMap is an alias for mergeMap because it is safer than concatMap, as concatMap would require buffering without back-pressure. Introduce back-pressure in the protocol, and concatMap becomes safer and much more efficient if done wisely. Which is cool because it is concatMap that's the monadic bind. And many other operations become more efficient and easier to implement because you no longer need to do buffering all over the place. In terms of those AsyncIterators, or whatever they are called, I tried that route but the model is terrible as you're forced to introduce asynchronous boundaries on each pull. This means the model is very inefficient. And I'm going to make another claim. Erik Meijer doesn't know what he's talking about in this case, in spite of how awesome he is and this opinion is probably the reason for why the Rx.NET library is trailing behind most Rx implementations. If I'd have to use .NET for a project, I'd probably end up reimplementing Monix, as Rx.NET isn't suitable for my use-cases at all.
- inglor 10y agoNo, they're eager - I had this mixed up too until Erik Meijer set me straight: > Now back to your question. I do not understand what you mean by “observables being fundamentally lazy”. I’d need to understand what you mean by that before I can give a coherent answer. Iterables are essentially lazy, because nothing happens before you call “moveNext”, but I’d categorize observables as (hyper) strict since “onNext” gets called wether or not the consumer wants it (so to speak).
- agentgt 10y agoI think I understand the eager confusion. You mean eager because it is a push model and not a pull model like iterator which is lazy. They are eager once Subscribed. The lazy part that I and the previous poster was alluding to is that most observables do nothing till they are subscribed to unless they are hot where as a Promise and Future are executed/scheduled immediately and the value is pushed/pulled (respectively). I totally agree that Observables are not that great for backpressure but really there isn't a silver bullet on that one regardless (many smart people have tried to come up with solutions that will work across domains but have failed). As you mentioned you just have to pick the right tool for the job/requirements. I for one prefer a broker ACK model like RabbitMQ but many do not like queues as it just shoves the problem some where else.
- bad_user 10y agoThe notion of hot versus cold for Promises/Futures doesn't make much sense, because you're not sharing a connection, but a result. In other words you're thinking of memoization of the result. Also backpressure doesn't make sense when you're pushing a single result, as there's nothing left to apply backpressure for. You mentioned Singles. I actually think Singles are terrible because they are observables. You see, while it's a poetic notion, the use cases are different. In particular, Futures tend to be used in tail recursive loops whereas observables are not used like that. So Futures can and must be stack safe (in flatMap), but Observables cannot be stack safe by definition (since you always have a last onComplete event). As a disclaimer, I've been working on a Scala library inspired by ReactiveX, Scala, Cats, etc. And my Task (i.e. Single) does not inherit from Observable. Try doing this with Single: https://monix.io/docs/2x/eval/task.html#flatmap-and-tail-recursive-loops https://monix.io/docs/2x/eval/task.html#flatmap-and-tail-rec...
- deleted 10y ago[deleted]