Packages

sealed trait IOLocal[A] extends AnyRef

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
A

the type of the local value

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

Abstract Value Members

  1. abstract def get: IO[A]

    Returns the current value.

  2. abstract 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

  3. abstract 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

  4. abstract 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

  5. abstract def reset: IO[Unit]

    Replaces the current value with the initial value.

  6. abstract def set(value: A): IO[Unit]

    Sets the current value to value.

  7. abstract def update(f: (A) => A): IO[Unit]

    Modifies the current value using the given update function.

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. def clone(): AnyRef
    Attributes
    protected[lang]
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.CloneNotSupportedException]) @native()
  6. final def eq(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  7. def equals(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef → Any
  8. def finalize(): Unit
    Attributes
    protected[lang]
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.Throwable])
  9. final def getClass(): Class[_ <: AnyRef]
    Definition Classes
    AnyRef → Any
    Annotations
    @native()
  10. def hashCode(): Int
    Definition Classes
    AnyRef → Any
    Annotations
    @native()
  11. final def isInstanceOf[T0]: Boolean
    Definition Classes
    Any
  12. final 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 ()
  13. final def ne(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  14. final def notify(): Unit
    Definition Classes
    AnyRef
    Annotations
    @native()
  15. final def notifyAll(): Unit
    Definition Classes
    AnyRef
    Annotations
    @native()
  16. final def synchronized[T0](arg0: => T0): T0
    Definition Classes
    AnyRef
  17. def toString(): String
    Definition Classes
    AnyRef → Any
  18. final def wait(): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException])
  19. final def wait(arg0: Long, arg1: Int): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException])
  20. final def wait(arg0: Long): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException]) @native()

Inherited from AnyRef

Inherited from Any

Ungrouped