Comparisons with Other Solutions

Comparing the Monix Observable with other solutions is no easy task. Yet we can try.

WARNING: This document contains opinions which are highly subjective! You won’t find unbiased comparisons from the authors of libraries. So take this with a grain of salt.

Akka Actors

Akka actors are a sort of a de facto solution for modeling message passing with Scala and the JVM. What they are good at:

But Akka actors aren’t suitable in many cases because:

By contrast the Monix Observable:

Reactive streaming libraries in general and the Monix Observable in particular is bad because they are good for modeling unidirectional communications, but it gets complicated if you want bidirectional communications (possible, but complicated), with actors being better at having dialogs.

Akka Streams

The Akka Streams project is also an implementation of reactive streams, but one that is based on Akka actors and that has its own design and opinions.

Why Monix is better:

Why Akka Streams might be better, depending on your preferences and needs:

HIGHLY OPINIONATED WARNING: The author of this document finds Akka Streams to be much more complicated.

The Monix Observable is basically the Observer pattern (from GoF) on steroids. But the Akka Streams implementation is not that and this has consequences of usability.

A stream of information is like a river. Does the river care who observes it or who drinks from it? It doesn’t. And indeed, sometimes you need to share the source between multiple listeners, sometimes you want to create new sources for each listener. But the listener shouldn’t care what sort of producer it has on its hands or vice-versa. And people are really not good at reasoning about graphs. And making those graphs explicit doesn’t make it better, it makes it worse.

In Monix you’ve got hot observables (hot data sources shared between an unlimited number of subscribers) and cold observables (each subscriber gets its very own private data source). You can also convert any cold data source into a hot one by using the multicast operator, in combination with Subjects that dictate behavior (e.g. Publish, Behavior, Async or Replay). And there’s no reason for the downstream subscribers to know the peculiarities of the upstream data-source. The philosophy of Monix is that this encapsulation is better.

In Akka Streams the sources have a “single output” port and what you do is you build “flow graphs” and sinks. Akka Streams is thus all about modeling how streams are split. They call it “explicit fan-out” and it’s a design choice. However this can be seen as an encapsulation leak that makes things more complicated and sometimes it defeats the purpose of using a library for streams manipulation in the first place. In ReactiveX and Monix terms, this is like having single-subscriber observable and then working with Subjects (which is both a listener and a producer) and people that have used ReactiveX know that working with Subjects is to be avoided, as that introduces complexity and extra worries in the system and when you do, you usually encapsulate it really, really well.

Akka Streams depends on Akka, the library. You suddenly worry about having an “Actor System” and a Materializer and a MessageFlowTransformer, with the tasks being executed by actors. This is way more heavy. One reason for why Scala’s Future and ExecutionContext are great is precisely because they model only asynchronous computations, but are completely oblivious to how the required asynchronous execution happens. This is why Future works on top of Scala.js without problems.

To its credit, the Akka Streams implementation does something smart. When you build a source and a flow, the goal has been to build a transformation flow and pass it around as a properly typed and inspectable object. Think abstract syntax trees (ASTs).

They have made this choice in order to encourage reuse of the actual stream blueprints instead of creating them again for every use, and it also nicely allows the addition of different Materializers that translate such a blueprint into its execution engine. In other words, it needs a Materializer to work, because the engine can thus transform those blueprints for execution on something other than actors. And if you don’t want actors, it’s theoretically possible to build a Materializer that executes the needed tasks on top of RxJava or on top of plain threads.

By comparison in the ReactiveX model (applicable to Monix as well) building observables happens by transforming one observable into another in functions that cannot be inspected. Which approach is better is a matter of opinion.

For Akka Streams, in practice, the only used materializer will be the ActorFlowMaterializer. And this extra flexibility has led to an opaque implementation. With Monix on the other hand, you can reason about what observables and subjects and subscribers are, you can reason about their implementation, whereas the inner workings of Akka Streams are harder to understand, confining developers using it to be plain users.

FS2 (the new Scalaz-Stream)

FS2 is a solid library for “streaming I/O” with a flourishing ecosystem.

Where FS2 is better:

It’s certainly a new and interesting approach, compatible with functional programming ideals. Where Monix is better: