Multiverse is a Java based STM implementation and last week I have been playing with integrating Multiverse in Scala. And since I have no practical experience with Scala and the Java language is not going anywhere (any more) it sounded like a nice opportunity to get started with Scala.
Multiverse supports 2 models for creating atomic objects (objects managed by the STM) in the Java language. The simplest approach is adding an @AtomicObject annotation to a Pojo:
@AtomicObject class Person{ private int age; public int getAge(){return age;} public void setAge(int newAge){this.age = newAge;} }
All changes made to person are atomic and isolated and the cool thing is that the get/setAge methods can participate in larger transactions (this solves the composability problem lock based approaches are suffering from). Using an @AtomicObject annotation is simple because you still can write normal Pojo’s.
The second model is using explicit refs (similar like Clojure refs).
class Person{ private final Ref age = new Ref(); public int getAge(){return age.get();} public void setAge(int newAge){age.set(newAge;} }
Multiverse doesn’t care which model is being used. The first has a better syntax and probably is going to perform better when the Pojo has more than 1 field (although it could also lead to false write-conflicts). But the second model is very easy to integrate with Scala and doesn’t rely on instrumentation. In the future the first model is going to be added to Scala as well, but I need to have a better understanding of how Scala is compiled to bytecode.
One of the cool things about Scala is that it is very easy to add new language constructs using closures. If we look at the atomic functionality (so wrapping a transaction around a set of operations) in Java, we need to write a lot of verbose code:
int sum = new AtomicTemplate(){ public Integer run(Transaction t){ return person1.getAge()+person2.getAge() } }.execute();
But in Scala you can say:
val sum = atomic{person1.age+person2.age}
Using the following closure:
def atomic[E](body: => E): E = { new AtomicTemplate[E] { def execute(t: Transaction) = body }.execute() }
Isn’t that cool?
In the following blogposts I’ll explain the support for the retry and orelse mechanisms.