TaskLocal

final class TaskLocal[A]

A TaskLocal is like a ThreadLocal that is pure and with a flexible scope, being processed in the context of the Task data type.

This data type wraps monix.execution.misc.Local.

Just like a ThreadLocal, usage of a TaskLocal is safe, the state of all current locals being transported over async boundaries (aka when threads get forked) by the Task run-loop implementation, but only when the Task reference gets executed with Task.Options.localContextPropagation set to true, or it uses a monix.execution.schedulers.TracingScheduler.

One way to achieve this is with Task.executeWithOptions, a single call is sufficient just before runToFuture:

 {
   import monix.execution.Scheduler.Implicits.global

   val t = Task(42)
   t.executeWithOptions(_.enableLocalContextPropagation)
     // triggers the actual execution
     .runToFuture
 }

Another possibility is to use Task.runToFutureOpt instead of runToFuture and specify the set of options implicitly:

 {
   import monix.execution.Scheduler.Implicits.global
   implicit val options: Task.Options = Task.defaultOptions.enableLocalContextPropagation

   val t = Task(42)
   // Options passed implicitly
   val f = t.runToFutureOpt
 }

Full example:

 import monix.eval.{Task, TaskLocal}

 val task: Task[Unit] =
   for {
     local <- TaskLocal(0)
     value1 <- local.read // value1 == 0
     _ <- local.write(100)
     value2 <- local.read // value2 == 100
     value3 <- local.bind(200)(local.read.map(_ * 2)) // value3 == 200 * 2
     value4 <- local.read // value4 == 100
     _ <- local.clear
     value5 <- local.read // value5 == 0
   } yield {
     // Should print 0, 100, 400, 100, 0
     println("value1: " + value1)
     println("value2: " + value2)
     println("value3: " + value3)
     println("value4: " + value4)
     println("value5: " + value5)
   }

 // For transporting locals over async boundaries defined by
 // Task, any Scheduler will do, however for transporting locals
 // over async boundaries managed by Future and others, you need
 // a `TracingScheduler` here:
 import monix.execution.Scheduler.Implicits.traced

 // Triggering actual execution,
 // runToFutureOpt is not needed if `TracingScheduler` is used
 val result = task.runToFuture
Companion:
object
class Object
trait Matchable
class Any

Value members

Concrete methods

def bind[R](value: A)(task: Task[R]): Task[R]

Binds the local var to a value for the duration of the given task execution.

Binds the local var to a value for the duration of the given task execution.

 // Should yield 200 on execution, regardless of what value
 // we have in `local` at the time of evaluation
 val task: Task[Int] =
   for {
     local <- TaskLocal(0)
     value <- local.bind(100)(local.read.map(_ * 2))
   } yield value
Value parameters:
task

is the Task to wrap, having the given value as the response to read queries and transported over asynchronous boundaries — on finish the local gets reset to the previous value

value

is the value to be set in this local var when the task evaluation is triggered (aka lazily)

See also:

bindL for the version with a lazy value.

def bindClear[R](task: Task[R]): Task[R]

Clears the local var to the default for the duration of the given task execution.

Clears the local var to the default for the duration of the given task execution.

 // Should yield 0 on execution, regardless of what value
 // we have in `local` at the time of evaluation
 val task: Task[Int] =
   for {
     local <- TaskLocal(0)
     value <- local.bindClear(local.read.map(_ * 2))
   } yield value
Value parameters:
task

is the Task to wrap, having the local cleared, returning the default as the response to read queries and transported over asynchronous boundaries — on finish the local gets reset to the previous value

def bindL[R](value: Task[A])(task: Task[R]): Task[R]

Binds the local var to a value for the duration of the given task execution, the value itself being lazily evaluated in the Task context.

Binds the local var to a value for the duration of the given task execution, the value itself being lazily evaluated in the Task context.

 // Should yield 200 on execution, regardless of what value
 // we have in `local` at the time of evaluation
 val task: Task[Int] =
   for {
     local <- TaskLocal(0)
     value <- local.bindL(Task.eval(100))(local.read.map(_ * 2))
   } yield value
Value parameters:
task

is the Task to wrap, having the given value as the response to read queries and transported over asynchronous boundaries — on finish the local gets reset to the previous value

value

is the value to be set in this local var when the task evaluation is triggered (aka lazily)

See also:

bind for the version with a strict value.

Clears the local value, making it return its default.

Clears the local value, making it return its default.

def local: Task[Local[A]]

Returns monix.execution.misc.Local instance used in this TaskLocal.

Returns monix.execution.misc.Local instance used in this TaskLocal.

Note that TaskLocal.bind will restore the original local value on the thread where the Task's run-loop ends up so it might lead to leaving local modified in other thread.

def read: Task[A]

Returns the current local value (in the Task context).

Returns the current local value (in the Task context).

def write(value: A): Task[Unit]

Updates the local value.

Updates the local value.