A few months ago, I discovered the oddly-named JavaScript library "bacon.js". Essentially, it lets you declare and compose event channels. While it seems overly abstract, the sample code intrigued me, as it introduced me to what is called "reactive programming".
Let's put this in context of typical UI programming. Let's say you want to write a GUI with a button that initiates a file download. You can't simply make the download synchronous, as it would "freeze" the entire GUI. The classical way to handle that is to create a new background thread that executes the download and also sends appropriate GUI events to display the state of the download.
The problem with that approach is that if you change the GUI, you now have to not only change the code that gets called when the download button is clicked, but also all the GUI updates done by the background thread. The GUI logic is intermingled with all the logic to start the thread, also intermingled with the download logic proper.
In more modern concurrency interfaces, the GUI code can spawn a new "Future", and describe what should happen when it completes outside of the code the Future will execute. This works well if the GUI doesn't have a download progress bar of some kind, and makes the download logic free of GUI logic. Still, this is risky: If for any reason the GUI vanishes (window closed, etc.), there is no easy way for the code related to the button click to describe how to cancel the background download, and when.
This is where "event channels" come into play. The most known implementation are the UNIX shells, where you would "pipe" one process' output to another's input. If the first process is terminated, the second process will get an interruption event when it attempts to read from the pipe, which by default cause the second process to be terminated. This is an easy way to create process groups, without having to explicitly tell the kernel about it.
Similar "process group" patterns exist in programming languages that support event communication between pseudo-processes or threads, for example the OTP Supervisor in Erlang.
Even will all of this (Futures, process pipes, supervisors), there are still a few things missing to make the implementation of a GUI download button simpler. First, there is no easy way to connect changes to mutable values, if the download button is active or not for example, to an event channel, and vice-versa. Basically, we need some kind of observer pattern, but applied to event handling. This has been my main gripe about MVC since, well, a long time ago. Also, there is no easy way to compose event channels together, even something as simple as aggregating multiple channel sources together into a new channel. While all that isn't terribly new in the networking world, with things like ZeroMQ and so on, in a programming environment without unreliability inherent in networking and no need for an interoperable packet-oriented stack, combining "networking" events together as a design pattern is quite compelling.
Hence why I was intrigued by bacon.js. It was inspired by the more comprehensive RxJs by Microsoft, and complements the React JavaScript library by Facebook. In fact, there even is a reactive programming manifesto, though it may be more the result of consultants hungry for the next wave of buzzwords than anything else. Still, it feels like what Aspect-Oriented Programming did to the Inversion of Control pattern, but applied to asynchronous event-based programming, which is to say that it brings it to a whole new level.
Published on September 15, 2015 at 19:46 EDT
Older post: 10s Everywhere
Newer post: The Twilight Zone: Top 10 Episodes (Spoilers-Free)