IEnumerable or IObservable, what’s the big diff?

The recent (it’s only been a couple of years) rise of Node.js roughly coincides with the rise of the “reactor” pattern of programming.  Of course it’s nothing new, but here it is in human form in a language and ‘platform’ that makes sense for the common programmer.

I’ve been contemplating these two patterns of recent as I’m trying to determine what’s the best way to handle mouse and keyboard actions in my little Raspberry Pi world.  It all comes down to having an “event loop” in your program.  And what should that event loop look like?

First of all, what kinds of events are we likely to see in a program?  Well, certainly there are keyboard and mouse events.  Increasingly, there are IO events, everything from a file descriptor becoming readable or writable (on Linux this includes sockets).  There are also ‘file stat’ events, which is things like file size, date modified, name changed, deleted, etc.  Then there’s timer types of events like “30 times a second”, or “once at 3pm”.  And of course there’s various “signal” types of events, like that interrupt you get when Control-C is pressed.

In my classical Windows programming, the event loop looks something like:

while (msg = GetMessage)
{
    TranslateMessage(msg)
    DispatchMessage(msg)
}

This is a classic IEnumerable loop if I ever did see one. Basically, there is a message queue, and you’ll pulling the messages off of that queue, and deciding what to do with them, typically dispatching them to routines within your system. A giant ‘dispatch table’ exists somewhere that deciphers the message, and sends it on to the next state.

You can spruce this loop up a bit, make it a bit more async by throwing in MsgWaitForMultipleObjectsEx (on Windows) and come up with the “ultimate game loop” like this:

  IsRunning = TRUE;
  while (IsRunning)
  {
    while ((bRet = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0))
    {
      if (bRet == -1)
      {
        // handle the error and possibly exit
      } else
      {
        BOOL success = TranslateMessage(&msg);
        LRESULT result = DispatchMessage(&msg);
      }
    }
    
    if (timeleft < 0)
    {
      timeleft = 0;
    }

    OnIdle();

    // use an alertable wait
    MsgWaitForMultipleObjectsEx(handleCount, handles, timeleft, QS_ALLEVENTS, dwFlags);

    OnTick(tickCount);
    tickCount = tickCount + 1;
}

This is kind of a hybrid. In the first part of the loop, there’s the PeekMessage(). If there are messages within the classic Windows message queue, they will all be pulled out and processed. If there aren’t any waiting, then move on to the next part of the loop. The ‘classic message queue’ contains all the keyboard, mouse, thread, and myriad other messages that are related to classic Win32 programming. The “DispatchMessage()” is pretty much the same thing as the Observable pattern. The messages will be handed to a typical dispatch routine, which will in turn parcel them out to various other functions that were registered to watch for them. For the rest of the events that don’t fit into the classic Windows eventing model, there is the MsgWaitForMultipleOjbectsEx(). This could include file descriptors, sockets, timers, and the like. In this particular case, we’re just watching for timer events. There’s a limit to the number of things you can watch for in this way though. If you want to observe a high number of network sockets, for example, then you need to use the more exotic IOCompletionPorts, which can deal with thousands of sockets.

But, this is still roughly the IEnumerable pattern. for the most part, ‘poll’ for the events, and mostly block waiting for them to happen.

Then there’s that IObservable pattern. In this pattern, there is something that emits events, and things that watch that something. The ’emitter’ can emit an observable event at any moment, and the watcher will observe that event ‘asynchronously’. Well, not really, and I think this is where the patter is misleading. Just because you have something called a ‘watcher’, and just because events can occur at any time, does not mean your system is asynchronous. The entirety of the system needs to be async if you want async processing. And this is true for both patterns.

So, the IObservable pattern is more like this:

emitter = SomethingThatEmitsEvents()

function OnMouseActivity(event)
    doWhatever();
end

function OnKeyActivity(event)
    doWhateverForKeys();
end

mouseobserver = MouseWatcher("/dev/input/mouse1", OnMouseActivity)
mouseobserver:StartObserving(emitter);

keyobserver = KeyWatcher("/dev/input/keyboard1", OnKeyActivity)
keyobserver:StartObserving(emitter);

emitter:Run();  -- Runs forever

The ’emitter’ runs an even loop, and it might look something like that which we created for the IEnumerable pattern internally, who knows. But externally, these functions that have been setup by the watchers will be called whenever an event of the specified type occurs.

By the time the OnKeyActivity or OnMouseActivity routines are called, we really can’t tell the difference between whether it was called through an IEnumerable pattern or an IObservable pattern. Go figure.

In fact, these two patterns are just two sides of the same coin. You can easily flip between IEnumerable and IObservable, by using a queue or some other mechanism to coordinate.

At any rate, IObservable seems to be in vogue these days, and this is what’s at the core of Node.js. Digging deeper, you find that it’s at the core of libuv, or libev even deeper still. And then digging into libev, you find these hard coded event type structures, and individual functions that know how to deal with each one of them, and further down into the bowels, you find either select, or Poll, or queue, or whatever to actually drive the event loop.

Coming back up for air, I begin to wonder. Is this the best that can be done? I don’t like those fixed data structures, and all the attendant code that goes with them. It seems so 80s. What if I plumb the depths of libev with Lua? What if instead of those fixed data structures, which inherently limit the types of events I can pump through my system, I instead utilized some more flexible Lua based data structures, and code?

This is the state of my current exploration. I’m taking libev and redoing it as much as possible as Lua code. I’m going all the way down to the system calls, and back up, to see what will result. I don’t know what the outcome will be, but I suspect that being able to construct either IObservable or IEnumerable will become a trivial matter, and can be easily constructed by the user, rather than be hard coded into the library.

At any rate, it’s a fun excursion to challenge the very foundations of what I have been relying on for highly performant web based services.

Advertisements


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s