What is difference between push based and pull based structures like IEnumerable<T> and IObservable<T>

  • A+

In every tech talk, or in every blog post I've read about IEnumerable and IObservable I read that, IEnumerable is pull-based structure and IObservable is push-based structure.

I've read that with IObservable we have async calls, where nothing is blocked and everything is push based.


What does it really means? Push based and pull based

Because in my opinion in IEnumerable we can also push data into the structure and also pull data from it, I've really lost in that technical terms and ideas.

Please in a normal and human way explain to me the difference between that two structure and difference between push-based and pull-based structures.



Please in a normal and human way explain to me the difference

OK, let's make some toast. That's the most normal human thing I do.

Pull based:

// I want some toast.  I will pull it out of the toaster when it is done. // I will do nothing until the toast is available. Toast t = toaster.MakeToast(); t.AddJam(); // Yum. 

Push based:

// I want some toast.  But it might take a while and I can do more work // while I am waiting: Task<Toast> task = toaster.MakeToastAsync(); Toast t = await task; // await returns to the caller if the toast is not ready, and assigns // a callback. When the toast is ready, the callback causes this method // to start again from this point: t.AddJam(); // Yum. 

You want to pull a result, you call a function and you do nothing else until the function returns.

You want a result pushed to you, you call an async function and await the result. When the result is available it is pushed at the callback, which resumes the method where it needs to be.

IEnumerable<T> is just a sequence of pulls; you call MoveNext every time you want to pull a result and you get a T. IObservable<T> is just a sequence of pushes; you register a callback, and it is called every time a new T is available.

Put another way: IEnumerable<T> is logically a sequence of Func<T> invocations. IObservable<T> is logically a sequence of Task<T> continuations. Don't let the fact that they are sequences confuse you; that's incidental. The fundamental idea is that functions are synchronous; you call them and get a result synchronously; if it takes a while, you wait. Tasks are asynchronous; you start them and get the result asynchronously when it is available.

This idea existed in C# before IObservable and await. Another way to look at is is: pull-based is like function calls, push-based is like event handlers. A normal function call, you call it when you want something. An event handler, it calls you when something happens. Events are how the C# language itself represents the observer pattern. But events always logically form a sequence, so it makes sense to be able to manipulate a sequence of pushed items the same way we'd manipulate a sequence of pulled items. And hence, IObservable was invented.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: