IOLocal provides a handy way of manipulating a context on different scopes.
In some scenarios, IOLocal can be considered as an alternative to cats.data.Kleisli.
IOLocal should not be treated as Ref, since the former abides different laws.
Once a fiber is forked, for example by Spawn[F].start
, the forked fiber manipulates the
copy of the parent's context. For example, two forked fibers will never see each other's
modifications to the same IOLocal, each fiber will only see its own modifications.
===Operations on IOLocal are visible to the fiber===
┌────────────┐ ┌────────────┐ ┌────────────┐
│ Fiber A │ update(_ + 1) │ Fiber A │ update(_ + 1) │ Fiber A │
│ (local 42) │──────────────►│ (local 43) │──────────────►│ (local 44) │
└────────────┘ └────────────┘ └────────────┘
def inc(name: String, local: IOLocal[Int]): IO[Unit] =
local.update(_ + 1) >> local.get.flatMap(current => IO.println(s"fiber $$name: $$current"))
for {
local <- IOLocal(42)
_ <- inc(1, local)
_ <- inc(2, local)
current <- local.get
_ <- IO.println(s"fiber A: $$current")
} yield ()
// output:
// update 1: 43
// update 2: 44
// fiber A: 44
===A forked fiber operates on a copy of the parent IOLocal===
A '''forked''' fiber (i.e. via Spawn[F].start
) operates on a '''copy''' of the parent
IOLocal
. Hence, the children operations are not reflected on the parent context.
┌────────────┐ ┌────────────┐
fork │ Fiber B │ update(_ - 1) │ Fiber B │
┌─────►│ (local 42) │──────────────►│ (local 41) │
│ └────────────┘ └────────────┘
┌────────────┐─┘ ┌────────────┐
│ Fiber A │ │ Fiber A │
│ (local 42) │────────────────────────────────────►│ (local 42) │
└────────────┘─┐ └────────────┘
│ ┌────────────┐ ┌────────────┐
│ fork │ Fiber C │ update(_ + 1) │ Fiber C │
└─────►│ (local 42) │──────────────►│ (local 43) │
└────────────┘ └────────────┘
def update(name: String, local: IOLocal[Int], f: Int => Int): IO[Unit] =
local.update(f) >> local.get.flatMap(current => IO.println(s"$$name: $$current"))
for {
local <- IOLocal(42)
fiber1 <- update("fiber B", local, _ - 1).start
fiber2 <- update("fiber C", local, _ + 1).start
_ <- fiber1.joinWithNever
_ <- fiber2.joinWithNever
current <- local.get
_ <- IO.println(s"fiber A: $$current")
} yield ()
// output:
// fiber B: 41
// fiber C: 43
// fiber A: 42
===Parent operations on IOLocal are invisible to children===
┌────────────┐ ┌────────────┐
fork │ Fiber B │ update(_ + 1) │ Fiber B │
┌─────►│ (local 42) │──────────────►│ (local 43) │
│ └────────────┘ └────────────┘
┌────────────┐─┘ ┌────────────┐
│ Fiber A │ update(_ - 1) │ Fiber A │
│ (local 42) │────────────────────────────────────►│ (local 41) │
└────────────┘─┐ └────────────┘
│ ┌────────────┐ ┌────────────┐
│ fork │ Fiber C │ update(_ + 2) │ Fiber C │
└─────►│ (local 42) │──────────────►│ (local 44) │
└────────────┘ └────────────┘
def update(name: String, local: IOLocal[Int], f: Int => Int): IO[Unit] =
IO.sleep(1.second) >> local.update(f) >> local.get.flatMap(current => IO.println(s"$$name: $$current"))
for {
local <- IOLocal(42)
fiber1 <- update("fiber B", local, _ + 1).start
fiber2 <- update("fiber C", local, _ + 2).start
_ <- fiber1.joinWithNever
_ <- fiber2.joinWithNever
_ <- update("fiber A", local, _ - 1)
} yield ()
// output:
// fiber B: 43
// fiber C: 44
// fiber A: 41
- Type parameters:
- A
the type of the local value
- Companion:
- object
- Source:
- IOLocal.scala
Value members
Abstract methods
Replaces the current value with the initial value, returning the previous value.
Replaces the current value with the initial value, returning the previous value.
- See also:
- Source:
- IOLocal.scala
Replaces the current value with value
, returning the previous value.
Replaces the current value with value
, returning the previous value.
- See also:
- Source:
- IOLocal.scala
Like update but allows the update function to return an output value of type B
.
Like update but allows the update function to return an output value of type B
.
- See also:
- Source:
- IOLocal.scala
Replaces the current value with the initial value.
Replaces the current value with the initial value.
- Source:
- IOLocal.scala
Modifies the current value using the given update function.
Modifies the current value using the given update function.
- Source:
- IOLocal.scala