liveBook · Manning

Ref

As explained in Functional Programming in Scala, Second Edition

Ref is a purely functional mutable-reference abstraction whose access and mutation are performed within an effect type.

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

How Functional Programming in Scala, Second Edition covers it

How deep it goes
Defines access, replacement, atomic modification, retry behavior, and construction, but does not develop a broader Ref API.
Examples
Uses a Ref for stream-scope state containing open or closed status, finalizers, and child scopes.
What it assumes
Assumes familiarity with effect types, monads, higher-kinded type parameters, and atomic references.
What you can do after
Build it from scratch with effect-wrapped reads, writes, atomic modifications, and a Monad-based constructor.
How it connects
Connects mutable cells to effect types, monads, atomic compare-and-set, streams, and resource safety.

This explainer was generated by Manning's knowledge graph from the text of Functional Programming in Scala, Second Edition. The section links point to the parts of the book it draws on.