Introducing MetaRx

December 21, 2015

As part of my Scala.js web framework Widok, I experimented with data binding mechanisms. The idea is to bind variables such that they trigger changes in the user interface.

A couple of users requested to extract this functionality into a separate library, so MetaRx was born. MetaRx gets cross-compiled for the JVM and therefore may be used even in UI frameworks such as Swing. For instance, sgine is a cross-platform UI framework which internally uses MetaRx for widget properties, animations and triggering recalculations.

MetaRx provides reactive counterparts for native data structures, such as variables, lists or maps. Their state is modelled as a stream of change objects, also called deltas. This design choice allows to effectively reduce the number of DOM updates. For example, when adding a row to a list, it would be wasteful to re-render it entirely. Instead, list operations get translated into atomic DOM updates.

Example

The following code example shows a reactive variable:

import pl.metastack.metarx._

val x = Var(1)

x.map(_ + 1)
 .filter(_ > 5)
 .attach(println)

(0 to 10).foreach(x := _)
Output:
6
7
8
9
10
11

Var is a channel which offers functional operations such as map() or flatMap().

Recent additions

In the latest version 0.1.4 a couple of new convenience features were introduced.

Implicits for arithmetic values

val x = Var(1.0)
val xOffset = 0.1
val vx = x + xOffset
vx.attach(println)
x := 2.0
Output:
1.1
2.1

Sub

Sub is short for subscription and its purpose is to take values as well as channels.

val x = Var(42)

val sub = Sub(23)
sub.attach(println)

sub := x  // `sub` will subscribe all values produced on `x`
x := 200  // Gets propagated to `sub`

sub := 10 // Cancel subscription and set value to 10
x := 404  // Doesn't get propagated to `sub`
Output:
23
42
200
10

Picklers

This feature relies on uPickle for serialising. Use it as follows:

import pl.metastack.metarx.Upickle._
import upickle.default._

val buffer = Buffer(1, 2, 3)

val json = write(buffer)
println(json)

val decoded = read[Buffer[Int]](json)
println(decoded)
Output:
[1,2,3]
ArrayBuffer(1, 2, 3)

Other changes

  • New combinator: takeWhile
  • ScalaTest for test cases
  • Multi-page manual

For more information, please have a look at the user manual.

Generated with MetaDocs v0.1.2-SNAPSHOT