cats.effect

package cats.effect

Type members

Classlikes

@implicitNotFound("Could not find an instance of Async for ${F}")
trait Async[F <: ([_$1] =>> Any)] extends Sync[F] with LiftIO[F]
A monad that can describe asynchronous or synchronous computations
that produce exactly one result.
==On Asynchrony==
An asynchronous task represents logic that executes independent of
the main program flow, or current callstack. It can be a task whose
result gets computed on another thread, or on some other machine on
the network.
In terms of types, normally asynchronous processes are represented as:
{{{
(A => Unit) => Unit
}}}
This signature can be recognized in the "Observer pattern" described
in the "Gang of Four", although it should be noted that without
an onComplete event (like in the Rx Observable pattern) you can't
detect completion in case this callback can be called zero or
multiple times.
Some abstractions allow for signaling an error condition
(e.g. MonadError data types), so this would be a signature
that's closer to Scala's Future#onComplete:
{{{
(Either[Throwable, A] => Unit) => Unit
}}}
And many times the abstractions built to deal with asynchronous tasks
also provide a way to cancel such processes, to be used in race
conditions in order to cleanup resources early:
{{{
(A => Unit) => Cancelable
}}}
This is approximately the signature of JavaScript's setTimeout,
which will return a "task ID" that can be used to cancel it.
N.B. this type class in particular is NOT describing cancelable
async processes, see the Concurrent type class for that.
==Async Type class==
This type class allows the modeling of data types that:
  1. can start asynchronous processes
  2. can emit one result on completion
  3. can end in error
N.B. on the "one result" signaling, this is not an ''exactly once''
requirement. At this point streaming types can implement Async
and such an ''exactly once'' requirement is only clear in Effect.
Therefore the signature exposed by the async
builder is this:
{{{
(Either[Throwable, A] => Unit) => Unit
}}}
N.B. such asynchronous processes are not cancelable.
See the Concurrent alternative for that.
Companion
object
object Async
Companion
class
final class Blocker extends AnyVal
An execution context that is safe to use for blocking operations.
Used in conjunction with ContextShift, this type allows us to write functions
that require a special ExecutionContext for evaluation, while discouraging the
use of a shared, general purpose pool (e.g. the global context).
Instances of this class should NOT be passed implicitly because they hold state
and in some cases your application may need different instances of Blocker.
Companion
object
object Blocker extends BlockerPlatform
Companion
class
trait Bracket[F <: ([_$1] =>> Any), E] extends MonadError[F, E]
An extension of MonadError exposing the bracket operation,
a generalized abstracted pattern of safe resource acquisition and
release in the face of errors or interruption.
Companion
object
object Bracket
Companion
class
@implicitNotFound("Cannot find an implicit value for Clock[${F}]:\n* import an implicit Timer[${F}] in scope or\n* create a Clock[${F}] instance with Clock.create\n")
trait Clock[F <: ([_$1] =>> Any)]
Clock provides the current time, as a pure alternative to:
Clock works with an F monadic context that can suspend
side effects (e.g. IO).
This is NOT a type class, as it does not have the coherence
requirement.
Companion
object
object Clock extends LowPriorityImplicits with ClockPlatform
Companion
class
@implicitNotFound("Could not find an instance of Concurrent for ${F}")
trait Concurrent[F <: ([_$1] =>> Any)] extends Async[F]
Type class for Async data types that are cancelable and
can be started concurrently.
Thus this type class allows abstracting over data types that:
  1. implement the Async algebra, with all its restrictions
  2. can provide logic for cancellation, to be used in race
    conditions in order to release resources early
    (in its cancelable builder)
Due to these restrictions, this type class also affords to describe
a start operation that can start async
processes, suspended in the context of F[_] and that can be
canceled or joined.
Without cancellation being baked in, we couldn't afford to do it.
See below.
==Cancelable builder==
The signature exposed by the cancelable
builder is this:
{{{
(Either[Throwable, A] => Unit) => CancelToken[F]
}}}
CancelToken[F] is just an alias for F[Unit] and
used to represent a cancellation action which will send a signal
to the producer, that may observe it and cancel the asynchronous
process.
==On Cancellation==
Simple asynchronous processes, like Scala's Future, can be
described with this very basic and side-effectful type and you
should recognize what is more or less the signature of
Future#onComplete or of Async.async (minus the error
handling):
{{{
(A => Unit) => Unit
}}}
But many times the abstractions built to deal with asynchronous
tasks can also provide a way to cancel such processes, to be used
in race conditions in order to cleanup resources early, so a very
basic and side-effectful definition of asynchronous processes that
can be canceled would be:
{{{
(A => Unit) => CancelToken
}}}
This is approximately the signature of JavaScript's setTimeout,
which will return a "task ID" that can be used to cancel it. Or of
Java's ScheduledExecutorService#schedule, which will return a
Java ScheduledFuture that has a .cancel() operation on it.
Similarly, for Concurrent data types, we can provide
cancellation logic that can be triggered in race conditions to
cancel the on-going processing, only that Concurrent's
cancelation token is an action suspended in an F[Unit].
Suppose you want to describe a "sleep" operation, like that described
by Timer to mirror Java's ScheduledExecutorService.schedule
or JavaScript's setTimeout:
{{{
def sleep(d: FiniteDuration): F[Unit]
}}}
This signature is in fact incomplete for data types that are not
cancelable, because such equivalent operations always return some
cancellation token that can be used to trigger a forceful
interruption of the timer. This is not a normal "dispose" or
"finally" clause in a try/catch block, because "cancel" in the
context of an asynchronous process is ''concurrent'' with the
task's own run-loop.
To understand what this means, consider that in the case of our
sleep as described above, on cancellation we'd need a way to
signal to the underlying ScheduledExecutorService to forcefully
remove the scheduled Runnable from its internal queue of
scheduled tasks, ''before'' its execution. Therefore, without a
cancelable data type, a safe signature needs to return a
cancellation token, so it would look like this:
{{{
def sleep(d: FiniteDuration): F[(F[Unit] , F[Unit] )]
}}}
This function is returning a tuple, with one F[Unit] to wait for
the completion of our sleep and a second F[Unit] to cancel the
scheduled computation in case we need it. This is in fact the shape
of Fiber's API. And this is exactly what the
start operation returns.
The difference between a Concurrent data type and one that
is only Async is that you can go from any F[A] to a
F[Fiber[F, A]], to participate in race conditions and that can be
canceled should the need arise, in order to trigger an early
release of allocated resources.
Thus a Concurrent data type can safely participate in race
conditions, whereas a data type that is only Async cannot do it
without exposing and forcing the user to work with cancellation
tokens. An Async data type cannot expose for example a start
operation that is safe.
== Resource-safety ==
Concurrent data types are required to cooperate with Bracket.
Concurrent being cancelable by law, what this means for the
corresponding Bracket is that cancelation can be observed and
that in the case of bracketCase the
ExitCase.Canceled branch will get executed on cancelation.
By default the cancelable builder is derived from bracketCase
and from asyncF, so what this means is that
whatever you can express with cancelable, you can also express
with bracketCase.
For uncancelable, the cancel
signal has no effect on the result of join and
the cancelable token returned by ConcurrentEffect.runCancelable
on evaluation will have no effect if evaluated.
So uncancelable must undo the cancellation mechanism of
cancelable, with this equivalence:
{{{
F.uncancelable(F.cancelable { cb => f(cb); token }) <-> F.async(f)
}}}
Sample:
{{{
val F = Concurrent[IO]
val timer = Timer[IO]
// Normally Timer#sleep yields cancelable tasks
val tick = F.uncancelable(timer.sleep(10.seconds))
// This prints "Tick!" after 10 seconds, even if we are
// canceling the Fiber after start:
for {
fiber <- F.start(tick)
_ <- fiber.cancel
_ <- fiber.join
_ <- F.delay { println("Tick!") }
} yield ()
}}}
When doing bracket or bracketCase,
acquire and release operations are guaranteed to be uncancelable as well.
Companion
object
object Concurrent
Companion
class
@implicitNotFound("Could not find an instance of ConcurrentEffect for ${F}")
trait ConcurrentEffect[F <: ([_$1] =>> Any)] extends Concurrent[F] with Effect[F]
Type class describing effect data types that are cancelable.
In addition to the algebras of Concurrent and of
Effect, instances must also implement a
runCancelable operation that
triggers the evaluation, suspended in the IO context, but that
also returns a token that can be used for canceling the running
computation.
Note this is the safe and generic version of IO.unsafeRunCancelable.
Companion
object
Companion
class
@implicitNotFound("Cannot find an implicit value for ContextShift[${F}]:\n* import ContextShift[${F}] from your effects library\n* if using IO, use cats.effect.IOApp or build one with cats.effect.IO.contextShift\n")
trait ContextShift[F <: ([_$1] =>> Any)]
ContextShift provides support for shifting execution.
The shift method inserts an asynchronous boundary, which moves execution
from the calling thread to the default execution environment of F.
The evalOn method provides a way to evaluate a task on a specific execution
context, shifting back to the default execution context after the task completes.
This is NOT a type class, as it does not have the coherence
requirement.
Companion
object
object ContextShift
Companion
class
@implicitNotFound("Could not find an instance of Effect for ${F}")
trait Effect[F <: ([_$1] =>> Any)] extends Async[F]
A monad that can suspend side effects into the F context and
that supports lazy and potentially asynchronous evaluation.
This type class is describing data types that:
  1. implement the Async algebra
  2. implement a lawful runAsync operation
    that triggers the evaluation (in the context of IO)
Note this is the safe and generic version of IO.unsafeRunAsync
(aka Haskell's unsafePerformIO).
Companion
object
object Effect
Companion
class
sealed abstract class ExitCase[+E] extends Product with Serializable
Type for signaling the exit condition of an effectful
computation, that may either succeed, fail with an error or
get canceled.
The types of exit signals are:
  • Completed: for successful
    completion (from the type of view of this MonadError)
  • Error: for termination in failure
    (via MonadError[F, E])
  • Canceled: for abortion
Companion
object
object ExitCase
Companion
class
sealed abstract case class ExitCode
Represents the exit code of an application.
code is constrained to a range from 0 to 255, inclusive.
Companion
object
object ExitCode
Companion
class
trait Fiber[F <: ([_$1] =>> Any), A]
Fiber represents the (pure) result of a Concurrent data type (e.g. IO)
being started concurrently and that can be either joined or canceled.
You can think of fibers as being lightweight threads, a fiber being a
concurrency primitive for doing cooperative multi-tasking.
For example a Fiber value is the result of evaluating IO.start:
{{{
val io = IO.shift *> IO(println("Hello!"))
val fiber: IO[Fiber[IO, Unit] ] = io.start
}}}
Usage example:
{{{
for {
fiber <- IO.shift *> launchMissiles.start
_ <- runToBunker.handleErrorWith { error =>
// Retreat failed, cancel launch (maybe we should
// have retreated to our bunker before the launch?)
fiber.cancel *> IO.raiseError(error)
}
aftermath <- fiber.join
} yield {
aftermath
}
}}}
Companion
object
object Fiber extends FiberInstances
Companion
class
sealed abstract class IO[+A] extends IOBinaryCompat[A]
A pure abstraction representing the intention to perform a
side effect, where the result of that side effect may be obtained
synchronously (via return) or asynchronously (via callback).
IO values are pure, immutable values and thus preserve
referential transparency, being usable in functional programming.
An IO is a data structure that represents just a description
of a side effectful computation.
IO can describe synchronous or asynchronous computations that:
  1. on evaluation yield exactly one result
  2. can end in either success or failure and in case of failure
    flatMap chains get short-circuited (IO implementing
    the algebra of MonadError)
  3. can be canceled, but note this capability relies on the
    user to provide cancellation logic
Effects described via this abstraction are not evaluated until
the "end of the world", which is to say, when one of the "unsafe"
methods are used. Effectful results are not memoized, meaning that
memory overhead is minimal (and no leaks), and also that a single
effect may be run multiple times in a referentially-transparent
manner. For example:
{{{
val ioa = IO { println("hey!") }
val program = for {
_ <- ioa
_ <- ioa
} yield ()
program.unsafeRunSync()
}}}
The above will print "hey!" twice, as the effect will be re-run
each time it is sequenced in the monadic chain.
IO is trampolined in its flatMap evaluation. This means that
you can safely call flatMap in a recursive function of arbitrary
depth, without fear of blowing the stack.
{{{
def fib(n: Int, a: Long = 0, b: Long = 1): IO[Long] =
IO(a + b).flatMap { b2 =>
if (n > 0)
fib(n - 1, b, b2)
else
IO.pure(a)
}
}}}
Companion
object
object IO extends IOInstances
Companion
class
trait IOApp
App type that runs a cats.effect.IO. Shutdown occurs after
the IO completes, as follows:
  • If completed with ExitCode.Success, the main method exits and
    shutdown is handled by the platform.
  • If completed with any other ExitCode, sys.exit is called
    with the specified code.
  • If the IO raises an error, the stack trace is printed to
    standard error and sys.exit(1) is called.
When a shutdown is requested via a signal, the IO is canceled and
we wait for the IO to release any resources. The process exits
with the numeric value of the signal plus 128.
{{{
import cats.effect._
import cats.syntax.all._
object MyApp extends IOApp {
def run(args: List[String] ): IO[ExitCode] =
args.headOption match {
case Some(name) =>
IO(println(s"Hello, ${name}.")).as(ExitCode.Success)
case None =>
IO(System.err.println("Usage: MyApp name")).as(ExitCode(2))
}
}
}}}
Companion
object
object IOApp extends IOAppCompanionPlatform
Companion
class
@implicitNotFound("Could not find an instance of LiftIO for ${F}")
trait LiftIO[F <: ([_$1] =>> Any)] extends Serializable
Companion
object
object LiftIO
Companion
class
sealed abstract class Resource[+F <: ([_$1] =>> Any), +A] extends ResourceLike[F, A]
The Resource is a data structure that captures the effectful
allocation of a resource, along with its finalizer.
This can be used to wrap expensive resources. Example:
{{{
def open(file: File): Resource[IO, BufferedReader] =
Resource(IO {
val in = new BufferedReader(new FileReader(file))
(in, IO(in.close()))
})
}}}
Usage is done via use and note that resource usage nests,
because its implementation is specified in terms of Bracket:
{{{
open(file1).use { in1 =>
open(file2).use { in2 =>
readFiles(in1, in2)
}
}
}}}
Resource forms a MonadError on the resource type when the
effect type has a cats.MonadError instance. Nested resources are
released in reverse order of acquisition. Outer resources are
released even if an inner use or release fails.
{{{
def mkResource(s: String) = {
val acquire = IO(println(s"Acquiring $$s")) *> IO.pure(s)
def release(s: String) = IO(println(s"Releasing $$s"))
Resource.make(acquire)(release)
}
val r = for {
outer <- mkResource("outer")
inner <- mkResource("inner")
} yield (outer, inner)
r.use { case (a, b) =>
IO(println(s"Using $$a and $$b"))
}
}}}
On evaluation the above prints:
{{{
Acquiring outer
Acquiring inner
Using outer and inner
Releasing inner
Releasing outer
}}}
A Resource is nothing more than a data structure, an ADT, described by
the following node types and that can be interpreted if needed:
Normally users don't need to care about these node types, unless conversions
from Resource into something else is needed (e.g. conversion from Resource
into a streaming data type).
Type Params
A
the type of resource
F
the effect type in which the resource is allocated and released
Companion
object
object Resource extends ResourceInstances with ResourcePlatform
Companion
class
@implicitNotFound("Could not find an instance of Sync for ${F}")
trait Sync[F <: ([_$1] =>> Any)] extends BracketThrow[F] with Defer[F]
A monad that can suspend the execution of side effects
in the F[_] context.
Companion
object
object Sync
Companion
class
@implicitNotFound("Could not find an instance of SyncEffect for ${F}")
trait SyncEffect[F <: ([_$1] =>> Any)] extends Sync[F]
A monad that can suspend side effects into the F context and
that supports only synchronous lazy evaluation of these effects.
Companion
object
object SyncEffect
Companion
class
final class SyncIO[+A]
A pure abstraction representing the intention to perform a
side effect, where the result of that side effect is obtained
synchronously.
SyncIO is similar to IO, but does not support asynchronous
computations. Consequently, a SyncIO can be run synchronously
to obtain a result via unsafeRunSync. This is unlike
IO#unsafeRunSync, which cannot be safely called in general --
doing so on the JVM blocks the calling thread while the
async part of the computation is run and doing so on Scala.js
throws an exception upon encountering an async boundary.
Companion
object
object SyncIO extends SyncIOInstances
Companion
class
@implicitNotFound("Cannot find an implicit value for Timer[${F}]:\n* import Timer[${F}] from your effects library\n* if using IO, use cats.effect.IOApp or build one with cats.effect.IO.timer\n")
trait Timer[F <: ([_$1] =>> Any)]
Timer is a scheduler of tasks.
This is the purely functional equivalent of:
It provides:
  1. the ability to get the current time
  2. ability to delay the execution of a task with a specified time duration
It does all of that in an F monadic context that can suspend
side effects and is capable of asynchronous execution (e.g. IO).
This is NOT a type class, as it does not have the coherence
requirement.
Companion
object
object Timer
Companion
class

Types

type ApplicativeThrow[F <: ([_$2] =>> Any)] = ApplicativeError[F, Throwable]
type BracketThrow[F <: ([_$4] =>> Any)] = Bracket[F, Throwable]
type CancelToken[F <: ([_$1] =>> Any)] = F[Unit]
A cancelation token is an effectful action that is
able to cancel a running task.
This is just an alias in order to clarify the API.
For example seeing CancelToken[IO] instead of IO[Unit]
can be more readable.
Cancelation tokens usually have these properties:
  1. they suspend over side effectful actions on shared state
  2. they need to be idempotent
Note that in the case of well behaved implementations like
that of IO idempotency is taken care of by its internals
whenever dealing with cancellation tokens, but idempotency
is a useful property to keep in mind when building such values.
type MonadThrow[F <: ([_$3] =>> Any)] = MonadError[F, Throwable]