Reactive Ruby is an experimental reactive language, which extends Truffle Ruby. It supports speculative just in time compilation via the Graal VM, which is a research VM from Oracle Labs. Reactive Ruby was initially started as a student’s thesis at the TU Darmstadt.
Reactive Ruby adds Behaviors to Truffle Ruby. Behaviors represent values which change over time. In general Behaviors represent a functional dependency over other Behaviors (the behavior expression). Whenever the value of a behavior changes Reactive Ruby ensures that the values of all other Behaviors are valid (reevaluates the behavior expression if necessary).
The following example demonstrates the general concept of reactive programming in Reactive Ruby.
range = rangeB(1,100)
even = range.filter(0) { |x|
x.to_i % 2 == 0
}
sum = even.fold ( 0 ) { |acc , val|
acc + val
}
combine = range.map(sum) { |x , y| [x , y] }
combine.onChange {|x| puts "sum: #{x}"}
In this example, method rangeB(1,100) creates a behavior which initially holds the value 1 and then stepwise increases until it holds the value 100. The range.filter creates behavior even which holds the last even value of range. Then range.fold produces behavior sum that adds up over all values of the behavior even. After that, range.map combines behaviors range and behavior sum. The value of this behavior is printed whenever it changes.
More information about the languages and its implementation are in the written thesis at: Thesis
The current version of Reactive Ruby is not yet updated to the newest Graal and Truffle version. Reactive Ruby requires Truffle and Graal from the change set 22218:aebb7c58725d. A mirror of the used Graal hg repository is at: Graal Mirror
The jt tool can be used to execute Reactive Ruby programs. (See: https://github.com/jruby/jruby/tree/master/truffle#workflow-tool)
jt run --graal examples/time.rb
executes the following example which prints the current time every second.
time = timeB(1)
time.onChange { |x| puts x}
jt run --graal examples/sum.rb
executes the next example, which demonstrates some operators.
range = rangeB(1,100)
even = range.filter(0) { | x |
x.to_i % 2 == 0
}
sum = even.fold( 0 ) { |acc, val|
acc + val
}
combine = range.map(sum) { | x, y | [x,y] }
combine.onChange {|x| puts "sum: #{x}"}
The output is:
sum: [2, 2]
sum: [3, 2]
sum: [4, 6]
sum: [5, 6]
sum: [6, 12]
sum: [7, 12]
sum: [8, 20]
sum: [9, 20]
sum: [10, 30]
...