5 min read

Every second, three new humans are born. Sometimes it feels like the buzz words are appearing with the same or even greater speed. In the last several years the word reactive became something everybody talked about, but it has different meanings. Wikipedia defines reactive programming in the following way:

Reactive programming is a programming paradigm oriented around data flows and the propagation of change.

This sounds cool, but it’s hard to comprehend. The reactivemanifesto.org site defines reactive systems as ones that are:

  • Responsive
  • Resilient
  • Elastic
  • Message driven

Moreover, this is something backed by Lightbend (the company behind Scala and one of the most active evangelists of the Reactive concept). The concept of Reactive became even harder to define lately because some UI-related frameworks claim to be Reactive: RxSwift or ReactiveCocoa for instance.

So, why would I be writing about something I called a buzzword? I believe that the Reactive approach is in its early stages, and we (the community) have not yet comprehended and structured it enough.

In this post I will cover the most significant tools in Reactive programming. Right now I’m working on a Swift Express project, which I want to be fully compliant with the reactivemanifesto.org. To accomplish this, I had to spawn a fully featured implementation of the Reactive foundation for Swift: Reactive Swift. Furthermore, I want this project to be suitable for both the client and the server side, which is quite a challenge.

The first thing I will describe is the RunLoop, which is a very basic low-level object, but it’s crucial for deep asynchronous programming understanding and, of course, implementation.

Run Loops

A traditional approach to the IO and long-lasting operations is blocking. Of course, there are threads, you can say, but threads are not cheap, and thread management is usually quite a cumbersome task for a developer.

Threads were invented to make our applications more responsive, right? OK, there are two main reasons apps don’t become responsive:

  1. Blocking IO
  2. CPU-heavy tasks

The second reason is becoming less and less relevant as hardware evolves, and it’s solvable with Reactive patterns in the same way as IO, so let’s focus on IO operations.

The traditional pseudocode for reading a file is as follows:

let file = open("filename")
//here we block
let data = file.readAll()

//do something with data

In the era of console apps, it was ok, since most of them were intended to perform single serial tasks (cat, grep, and so on). But if we do something like that on the main execution loop in the UI app, it will hang until the file is fully read. If we do it in a single-threaded server, it will block the accepting and serving of new requests. Thus, threads were made. The real problem, though, is that we just need the data to become available in the future without stopping other operations.

In the C language, you can find several implementations of these on different platforms, like epoll on Linux and kqueue on FreeBSD and OS X (all low-level and hard to work with). Still, what is common about them is that they all are Run Loops in essence.

Wikipedia defines Run Loops as follows:

A run loop is a programming construct that waits for and dispatches events or messages in a program.

In practice, it looks like this (Swift pseudocode):

let loop = RunLoop()

//here we block and start processing messages
loop.run()

Each operation on the loop should not last long, and if there is nothing to do, the loop sleeps. It can process IO operations and can have operations to be scheduled for later execution. Here is how it would look to read a file with an event loop:

// remember we already have a loop from the previous listing?
let file = open("filename", loop: loop)

//here we do NOT block
file.readAll { data in
    //do something with data
}

//here we assume the loop is running, and the code above is executed inside it

The trick is very simple. We don’t block for every single operation, but rather for all the operations together in the loop until an event happens (data availability, a timer is fired, an operation is due, and so on). As soon as the underlying OS is managing all of these states, it can unblock the loop when at least one event happens (think about the need to redraw the screen, accept new connection, and so on) and tell the loop which event exactly has happened and what it should execute. This way we can simultaneously wait for user input, a new incoming connection, and a response from a server without hanging the app.

This is called asynchronous approach. Not reactive programming yet, but the first step and an essential part of it (remember the “Message driven” item from reactivemanifesto.org‘s list?).

If you want to see more practical examples, take a look at our RunLoop from Reactive Swift foundation (sorry for the absence of a README). It’s something that we already use in all other parts of Reactive Swift, in the upcoming version (0.4) of Swift Express, and in our iOS apps. It has two underlying implementations and at the time of writing can work either with Dispatch or use libuv (the same is used by NodeJS) as a core engine.

I hope you enjoyed reading this.

About the author

Daniel Leping is the CEO of Crossroad Labs. He has been working with Swift since the early beta releases and continues to do so at Swift Express project. His main interests are reactive and functional programming with Swift and Swift-based web technologies and bringing the best of modern techniques to the Swift world. He can be found on GitHub.

LEAVE A REPLY

Please enter your comment!
Please enter your name here