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.

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 Params
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 Params
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 Params
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.

def clear: Task[Unit]

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.