A Ref is a mutable cell whose value is accessed and changed through an effect type. It keeps mutation explicit while allowing the surrounding program to compose operations as effects. section 15.6
An effectful mutable cell
A Ref[F, A] can expose get: F[A], set(a: A): F[Unit], and modify(f: A => (A, B)): F[B]. The modify operation reads the current value, computes a replacement and result, then retries with compare-and-set if another update intervenes. section 15.3.3
The abstraction separates the cell’s mutable storage from the program’s effectful interface. Its modify operation supports a state transition and a returned value in one composable action, which is useful when stream machinery tracks changing scope state. section 15.3.3 section 15.6
final class Ref[F[_], A] private (
underlying: AtomicReference[A],
delay: [A] => (() => A) => F[A] #1
):
def get: F[A] = delay(() => underlying.get)
def set(a: A): F[Unit] = delay(() => underlying.set(a))
def modify[B](f: A => (A, B)): F[B] = delay: () =>
@annotation.tailrec
def loop(): B =
val oldA = underlying.get
val (newA, result) = f(oldA)
if underlying.compareAndSet(oldA, newA) then result else loop()
loop()
object Ref:
def apply[F[_], A](initial: A)(using F: Monad[F]): Ref[F, A] =
new Ref(new AtomicReference[A](initial),
[A] => (th: () => A) => F.unit(()).map(_ => th()))
Inspect the complete Ref shape, including its effect-wrapped operations, atomic update loop, and constructor requiring a Monad. section 15.3.3
