Packages

sealed trait IOLocal[A] extends IOLocalPlatform[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(n: Int, local: IOLocal[Int]): IO[Unit] =
  local.update(_ + 1) >> local.get.flatMap(current => IO.println(s"update $$n: $$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
A

the type of the local value

Self Type
IOLocal[A]
Source
IOLocal.scala
Linear Supertypes
IOLocalPlatform[A], AnyRef, Any
Ordering
  1. Alphabetic
  2. By Inheritance
Inherited
  1. IOLocal
  2. IOLocalPlatform
  3. AnyRef
  4. Any
  1. Hide All
  2. Show All
Visibility
  1. Public
  2. Protected

Abstract Value Members

  1. abstract def getOrDefault(state: IOLocalState): A
    Attributes
    protected[effect]
  2. abstract def lens[B](get: (A) => B)(set: (A) => (B) => A): IOLocal[B]

    Creates a lens to a value of some type B from current value and two functions: getter and setter.

    Creates a lens to a value of some type B from current value and two functions: getter and setter.

    All changes to the original value will be visible via lens getter and all changes applied to 'refracted' value will be forwarded to the original via setter.

    Note that set method requires special mention: while from the IOLocal[B] point of view old value will be replaced with a new one, from IOLocal[A] POV old value will be updated via setter. This means that for 'refracted' IOLocal[B] use of set(b) is equivalent to reset *> set(b), but it does not hold for original IOLocal[A]:

    update(a => set(setter(a)(b)) =!= (reset *> update(default => set(setter(default)(b)))
    Example:
    1. for {
        base <- IOLocal(42 -> "empty")
        lens = base.lens(_._1) { case (_, s) => i => (i, s) }
        _    <- lens.update(_ + 1) // `42` is visible in lens closure
        _    <- base.get // returns `(43, "empty")`
        _    <- base.set(1 -> "some")
        _    <- lens.set(42)
        _    <- base.get // returns `(42, "some")`
      } yield ()
  3. abstract def reset(state: IOLocalState): IOLocalState
    Attributes
    protected[effect]
  4. abstract def set(state: IOLocalState, a: A): IOLocalState
    Attributes
    protected[effect]

Concrete Value Members

  1. final def !=(arg0: Any): Boolean
    Definition Classes
    AnyRef → Any
  2. final def ##: Int
    Definition Classes
    AnyRef → Any
  3. final def ==(arg0: Any): Boolean
    Definition Classes
    AnyRef → Any
  4. final def asInstanceOf[T0]: T0
    Definition Classes
    Any
  5. final def asLocal: Local[IO, A]
  6. def clone(): AnyRef
    Attributes
    protected[lang]
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.CloneNotSupportedException]) @native()
  7. final def eq(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  8. def equals(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef → Any
  9. def finalize(): Unit
    Attributes
    protected[lang]
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.Throwable])
  10. final def get: IO[A]

    Returns the current value.

  11. final 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.

    See also

    get

    reset

  12. final 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.

    See also

    get

    set

  13. final def getClass(): Class[_ <: AnyRef]
    Definition Classes
    AnyRef → Any
    Annotations
    @native()
  14. def hashCode(): Int
    Definition Classes
    AnyRef → Any
    Annotations
    @native()
  15. final def isInstanceOf[T0]: Boolean
    Definition Classes
    Any
  16. final 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.

    See also

    update

  17. final def ne(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  18. final def notify(): Unit
    Definition Classes
    AnyRef
    Annotations
    @native()
  19. final def notifyAll(): Unit
    Definition Classes
    AnyRef
    Annotations
    @native()
  20. final def reset: IO[Unit]

    Replaces the current value with the initial value.

  21. final def set(value: A): IO[Unit]

    Sets the current value to value.

  22. final def synchronized[T0](arg0: => T0): T0
    Definition Classes
    AnyRef
  23. def toString(): String
    Definition Classes
    AnyRef → Any
  24. def unsafeThreadLocal(): ThreadLocal[A]

    Returns a java.lang.ThreadLocal view of this IOLocal that allows to unsafely get, set, and remove (aka reset) the value in the currently running fiber.

    Returns a java.lang.ThreadLocal view of this IOLocal that allows to unsafely get, set, and remove (aka reset) the value in the currently running fiber. The system property cats.effect.trackFiberContext must be true, otherwise throws an java.lang.UnsupportedOperationException.

    Definition Classes
    IOLocalPlatform
  25. final def update(f: (A) => A): IO[Unit]

    Modifies the current value using the given update function.

  26. final def wait(): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException])
  27. final def wait(arg0: Long, arg1: Int): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException])
  28. final def wait(arg0: Long): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException]) @native()

Inherited from IOLocalPlatform[A]

Inherited from AnyRef

Inherited from Any

Ungrouped