Skip to main content
Version: 2.0.x

ScopedRef: Mutable Reference For Resources

ScopedRef is a resourceful version of Ref data type. So it is a Ref for resourceful effects.


There are two basic operations: get and set:

  • ScopedRef#get returns the current value of the scoped ref.

  • ScopedRef#set sets the scoped ref to a new value by acquiring the new resource to create a new value of the scoped ref. Setting a new value releases the old resource automatically.


The ScopedRef has two constructors:

object ScopedRef {
def make[A](a: => A): ZIO[Scope, Nothing, ScopedRef[A]] = ???
def fromAcquire[R, E, A](acquire: ZIO[R, E, A]): ZIO[R with Scope, E, ScopedRef[A]] = ???

So we have two options to create a ScopedRef:

  • ScopedRef.make creates a scoped ref from an ordinary value. We can use this constructor when we don't need to acquire a resource to create a value of the scoped ref, for example, when we have a constant value.

  • ScopedRef.fromAcquire creates a scoped ref from an effect that resourcefully produces a value.


ScopedRef is resourceful, so its lifetimes is scoped. Whenever we don't need it anymore, we can release it by using ZIO#scoped combinator.


Let's see how changing the value of a ScopedRef automatically releases the old resource:

import zio._

object MainApp extends ZIOAppDefault {
def run = for {
_ <- ZIO.unit
r1 = ZIO.acquireRelease(
.debug("acquiring the first resource")
)(_ => ZIO.debug("releasing the first resource"))
r2 = ZIO.acquireRelease(
.debug("acquiring the second resource")
)(_ => ZIO.debug("releasing the second resource"))
sref <- ScopedRef.fromAcquire(r1)
_ <- sref.get.debug
_ <- sref.set(r2)
_ <- sref.get.debug
} yield ()

The output:

acquiring the first resource
acquiring the second resource
releasing the first resource
releasing the second resource