17

How do you establish whether or not a method should return IEnumerable<T> or IObservable<T>?

Why would I choose one paradigm over the other?

Timothy Shields
  • 75,459
  • 18
  • 120
  • 173
jmcg
  • 357
  • 3
  • 12
  • 10
    That's like asking how to decide whether a method should return a List or a DateTime... The types aren't semantically related. – Matthew Watson Jun 13 '13 at 08:13
  • I agree with @MatthewWatson, both interfaces serves different purposes. – Oscar Jun 13 '13 at 08:16
  • They are both used to enumerate data streams - so when do I decide whether or not I should use one or the other? – jmcg Jun 13 '13 at 08:19
  • 2
    `IEnumerable` is for *pulling* data from a collection, `IObservable` is for subscribing to for *pushed* data. – Nick Jun 13 '13 at 08:21
  • 3
    They are not both enumerating. IEnumerable is basically like "give me the next item", IObservable is "hey look, there is the next item". – Dirk Jun 13 '13 at 08:22
  • That's not necessarily the case. That's more of a hot observable vs cold observable thing. – jmcg Jun 13 '13 at 08:23
  • @user2346896 IEnumerable represents a sequence of separate items; IObservable represents a temporally-dependent sequence of change events associated with a single item. – Matthew Watson Jun 13 '13 at 08:31
  • 7
    I would argue that IObservable and IEnumerableIObservable are *very* semantically related. They might be opposing in many respects, but that doesn't mean they are unrelated. In fact Eric Meijer has done several talks on this very point, a video of one can be found here: http://channel9.msdn.com/Shows/Going+Deep/Expert-to-Expert-Brian-Beckman-and-Erik-Meijer-Inside-the-NET-Reactive-Framework-Rx - it's also not a dumb question. There are many situations in which a choice between one or other has profound implications on a system's design. – James World Jun 13 '13 at 15:02
  • Oops... spotted a typo. Previous comment should have started "I would argue that `IObservable` and *`IEnumerable`*..." etc – James World Jun 13 '13 at 20:29

4 Answers4

28

Types

  • IEnumerable<T>
    • You repeatedly "pull" from a sequence of T's
  • IObservable<T>
    • A sequence of T's is being "pushed" at you

Why would I choose one paradigm over the other?

You typically don't "choose" one paradigm over the other. Usually one stands out naturally as the correct choice, with the other one not making any sense.

Examples

Consider the following examples:

  • A huge CSV text file has an item on each line, and you want to process them one at a time without loading the entire file into memory at once: IEnumerable<List<string>>

  • You are running an HTTP web server: IObservable<WebRequest>

  • You want to do get the nodes of a tree data structure in a breadth-first manner: IEnumerable<Node>

  • You are responding to user interface button clicks: IObservable<Click>

In each of these examples (especially the IObservable<T> cases), it just wouldn't make sense to use the other type.

But what if I want to use the "other" type...

IObservable<T> to IEnumerable<T>

If something is naturally an IObservable<T> but you want to process it as if it were an IEnumerable<T>, you can do that with this method:

IEnumerable<T> Observable.ToEnumerable(this IObservable<T>)
  • When a T gets "pushed" by the IObservable<T>, it gets sent into a queue.
  • When you try to "pull" a T out of the IEnumerable<T>, it blocks until the queue isn't empty, then dequeues.

IEnumerable<T> to IObservable<T>

If something is naturally an IEnumerable<T> but you want to process it as if it were an IObservable<T>, you can do that with this method:

IObservable<T> Observable.ToObservable(this IEnumerable<T>)
  • A thread from the .NET thread pool will repeatedly try to "pull" a T from the IEnumerable<T>.
  • Each time it "pulls" a T, it "pushes" it at you via the IObservable<T>.
Timothy Shields
  • 75,459
  • 18
  • 120
  • 173
8

Use IObservable<T> if you want to push data to callers of your method at your convenience. You do this by calling OnNext() on Observers that registered interest via Subscribe().

Use IEnumerable<T> if you want callers of your method to pull data at their convenience. They do this by calling GetEnumerator() to acquire an IEnumerator and calling MoveNext() and Current (foreach compiles to this).

UPDATE: Perhaps best to give some examples:

A function that returns currency prices in a bank is a good candidate for IObservable<T>. Here the information is time-critical. As the server of this data, you need to get it to the client as soon as possible. The client won't know when that data is ready. So you push it to them.

A function that returns the valid trading days for a particular financial instrument and is used to populate the blackout days on a calendar control is a good candidate for IEnumerable. This data rarely changes and the client (setting up the control) prefers to consume it at a pace it dictates.

James World
  • 29,019
  • 9
  • 86
  • 120
5

IObservable<T> is a specialized interface that can be used for pub/sub and various other patterns. You would know when you needed to return an IObservable<T>, so if there is not specific need then return IEnumerable<T>.

Update to question in comment

Basically, IObservable<> uses a "Push" mechanism and IEnumerable<> uses a "Pull" mechanism. If you are going to simply obtain a list of data that doesn't need to notify subscribers of changes (push) then you can use IEnumerable. If a subscriber (Window, Control, other Client programs/routines, etc...) needs to know when data changed then use IObservable<>. One example is using IObservable to update the main UI thread in a windows program from a child thread (Normally this cannot be done without fancy footwork. Read up on .NET Reactive Extensions (Rx.NET).

zx485
  • 28,498
  • 28
  • 50
  • 59
bbqchickenrobot
  • 3,592
  • 3
  • 45
  • 67
  • 1
    Why not always return IObservable instead of IEnumerable? Surley IObservable is a superset of the functionality? – jmcg Jun 13 '13 at 08:27
  • Not correct. You're describing Observable (the class). IObservable is merely an interface that provides change notifications - not necessarily to do with collections. – Simon Robinson Jun 13 '13 at 08:54
  • Added answer to your question above.... Thanks for catching that Simon - I'm tired and meant to write class. – bbqchickenrobot Jun 13 '13 at 08:58
1

Use IEnumerable<T> to represent lists, use IObservable<T> to represent events. Easy peasy.

Ana Betts
  • 73,868
  • 16
  • 141
  • 209