IOLocal

cats.effect.IOLocal
See theIOLocal companion object
sealed trait IOLocal[A]

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

Attributes

A

the type of the local value

Companion:
object
Source:
IOLocal.scala
Graph
Supertypes
class Object
trait Matchable
class Any

Members list

Concise view

Value members

Abstract methods

def get: IO[A]

Returns the current value.

Returns the current value.

Attributes

Source:
IOLocal.scala
def getAndReset: IO[A]

Replaces the current value with the initial value, returning the previous value.

Replaces the current value with the initial value, returning the previous value.

The combination of get and reset.

Attributes

See also:
Source:
IOLocal.scala
def getAndSet(value: A): IO[A]

Replaces the current value with value, returning the previous value.

Replaces the current value with value, returning the previous value.

The combination of get and set.

Attributes

See also:
Source:
IOLocal.scala
def modify[B](f: A => (A, B)): IO[B]

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.

Attributes

See also:
Source:
IOLocal.scala
def reset: IO[Unit]

Replaces the current value with the initial value.

Replaces the current value with the initial value.

Attributes

Source:
IOLocal.scala
def set(value: A): IO[Unit]

Sets the current value to value.

Sets the current value to value.

Attributes

Source:
IOLocal.scala
def update(f: A => A): IO[Unit]

Modifies the current value using the given update function.

Modifies the current value using the given update function.

Attributes

Source:
IOLocal.scala