What is the Scala equivalent of Clojure's Atom?
As @Shepmaster and @om-nom-nom said, it's a wrapper around java.util.concurrent.atomic.Atomic...
.
An equivalent wrapper could look like this:
import java.util.concurrent.atomic._import scala.annotation.tailrecobject Atom { def apply[A](init: A): Atom[A] = new Impl(new AtomicReference(init)) private class Impl[A](state: AtomicReference[A]) extends Atom[A] { def apply(): A = state.get() def update(value: A): Unit = state.set(value) def transformAndGet(f: A => A): A = transformImpl(f) @tailrec private final def transformImpl(fun: A => A): A = { val v = state.get() val newv = fun(v) if (state.compareAndSet(v, newv)) newv else transformImpl(fun) } }}trait Atom[A] { def apply(): A def update(value: A): Unit def transformAndGet(f: A => A): A}
Ex:
val myAtom = Atom(0)myAtom() // --> 0myAtom.transformAndGet(_ + 1) // --> 1myAtom() // --> 1myAtom.transformAndGet(_ * 4) // --> 4
If you use Scala-STM, that functionality is built into STM references, by using the .single
view:
scala> import scala.concurrent.stm._import scala.concurrent.stm._scala> val myAtom = Ref(0).singlemyAtom: scala.concurrent.stm.Ref.View[Int] = scala.concurrent.stm.ccstm.CCSTMRefs$IntRef@52f463b0scala> myAtom()res0: Int = 0scala> myAtom.transformAndGet(_ + 1)res1: Int = 1scala> myAtom()res2: Int = 1scala> myAtom.transformAndGet(_ * 4)res3: Int = 4
The advantage is that Ref.apply
will already give you specialised cells for the primitive types, e.g. Int
instead of AnyRef
(boxed).
It's not Scala-specific, but I'd reach for AtomicReference first in Java land. How much of atom
s functionality do you want/need?