Ingress to Monix-Eval: Task


Monix that is used for composing Asynchronous programs for Scala and Scala.js runs on JVM. Monix 2.0 is modular by design so you can pick and choose:

  • Monix-Execution: Scheduler, Cancelable, CancelableFuture and Atomic.
  • Monix-Eval: For controlling evaluation by means of Task, Coeval and TaskApp.
  • Monix-Reactive:  Observable.
  • Monix: Provides all of the above

Before we start learning Monix Tasks. Let’s first talk about what evaluation mean in scala.

Evaluation in Scala can be done in two ways:

  • Eager  –  Eager means whether you need the result or not it just evaluated before you need them.
  • Lazy– Lazy means result of an expression is evaluated on a need basis.

Above Eager and Lazy evaluation in scala are synchronous.

For Asynchronous we have:

  • Future – Future represents value, detached to time.
  • Task– Task has to do tricks in order to be “cancelable“, a trait that allows it to close opened resources when race conditions happen.

Below is an example that shows the difference between Scala Future and Monix Task:-

import scala.concurrent.ExecutionContext
import ExecutionContext.Implicits.global
import scala.concurrent.Future

val future =
   Future { 1 + 1 }

future.onComplete {
   case Success(value) =>
      println(value)
   case Failure(ex) =>
      println(ex.getMessage)
}

Task doesn’t trigger any effect until runAsync. It allows canceling the running computation.

// In order to evaluate tasks, we’ll need a Schedule

import monix.execution.scheduler
import Scheduler.Implicits.global
import monix.eval.Task

val task =
   task { 1 + 1 }

task.runAsync {
   case Success(value) =>
      println(value)
   case Failure(ex) =>
      println(ex.getMessage)
}

Simple Builders

//Strict evaluation

Task.now { println("effect"); "immediate" }

//Lazy/memoized evaluation

Task.evalOnce { println("effect"); "immediate" }

//Equivalent to Function

Task.evalAlways { println("effect"); "immediate" }

//Builds a factory of tasks

Task.defer(Task.now { println("effect") })

//Guarantees asynchronous execution

Task.fork(Task.evalAlways("Hello"))

Memoization:
You can take any task and memoize it means it executes once and you can get the result for subsequent evaluations. If you have side effect that it would be evaluated only once.

val task1 = Task.evalOnce("effect")
val task2 = Task.evalAlways("effect")

Future memoized by default but in Task if you want memoization you need to specify it explicitly.

val task3 = Task.evalAlways("effect").memoize

Tail Recursive Loops Example:-

def fib(cycles: Int, a: BigInt, b: BigInt): BigInt =
   if(cycles > 0)
      fib(cycles - 1,  b,  a + b)
   else
      b

You can describe it using Task. You use Task.defer to transform it to a lazy evaluation and Task.now to get the result.

def fib(cycles: Int, a: BigInt, b: BigInt): Task[BigInt] =
    if(cycles > 0)
      Task.defer(fib(cycles - 1,  b,  a + b))
    else
      Task.now(b)

We can use flatmap in place of defer that describes recursivity.

def fib(cycles: Int, a: BigInt, b: BigInt): Task[BigInt] =
  Task.evalAlways(cycles > 0).flatMap {
     case true =>
        fib(cycles - 1, b,  a + b)
     case false =>
        Task.now(b)
}

References: Monix Official Documentation
Thanks For Reading!! Happy Coding 🙂
KNOLDUS-advt-sticker

This entry was posted in Scala and tagged , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s