Creates a simple, non-cancelable F[A]
instance that
executes an asynchronous process on evaluation.
Creates a simple, non-cancelable F[A]
instance that
executes an asynchronous process on evaluation.
The given function is being injected with a side-effectful callback for signaling the final result of an asynchronous process.
This operation could be derived from asyncF, because:
F.async(k) <-> F.asyncF(cb => F.delay(k(cb)))
As an example of wrapping an impure async API, here's the implementation of Async.shift:
def shift[F[_]](ec: ExecutionContext)(implicit F: Async[F]): F[Unit] = F.async { cb => // Scheduling an async boundary (logical thread fork) ec.execute(new Runnable { def run(): Unit = { // Signaling successful completion cb(Right(())) } }) }
is a function that should be called with a callback for signaling the result once it is ready
asyncF for the variant that can suspend side effects in the provided registration function.
Creates a simple, non-cancelable F[A]
instance that
executes an asynchronous process on evaluation.
Creates a simple, non-cancelable F[A]
instance that
executes an asynchronous process on evaluation.
The given function is being injected with a side-effectful
callback for signaling the final result of an asynchronous
process. And its returned result needs to be a pure F[Unit]
that gets evaluated by the runtime.
Note the simpler async variant async can be derived like this:
F.async(k) <-> F.asyncF(cb => F.delay(k(cb)))
For wrapping impure APIs usually you can use the simpler async,
however asyncF
is useful in cases where impure APIs are
wrapped with the help of pure abstractions, such as
Ref.
For example here's how a simple, "pure Promise" implementation
could be implemented via Ref
(sample is for didactic purposes,
as you have a far better
Deferred available):
import cats.effect.concurrent.Ref type Callback[-A] = Either[Throwable, A] => Unit class PurePromise[F[_], A](ref: Ref[F, Either[List[Callback[A]], A]]) (implicit F: Async[F]) { def get: F[A] = F.asyncF { cb => ref.modify { case current @ Right(result) => (current, F.delay(cb(Right(result)))) case Left(list) => (Left(cb :: list), F.unit) } } def complete(value: A): F[Unit] = F.flatten(ref.modify { case Left(list) => (Right(value), F.delay(list.foreach(_(Right(value))))) case right => (right, F.unit) }) }
N.B. if F[_]
is a cancelable data type (i.e. implementing
Concurrent), then the returned F[Unit]
can be cancelable,
its evaluation hooking into the underlying cancelation mechanism
of F[_]
, so something like this behaves like you'd expect:
def delayed[F[_], A](thunk: => A) (implicit F: Async[F], timer: Timer[F]): F[A] = { timer.sleep(1.second) *> F.delay(cb( try cb(Right(thunk)) catch { case NonFatal(e) => Left(cb(Left(e))) } )) }
The asyncF
operation behaves like Sync.suspend, except
that the result has to be signaled via the provided callback.
As a matter of contract the returned F[Unit]
should not
throw errors. If it does, then the behavior is undefined.
This is because by contract the provided callback should
only be called once. Calling it concurrently, multiple times,
is a contract violation. And if the returned F[Unit]
throws,
then the implementation might have called it already, so it
would be a contract violation to call it without expensive
synchronization.
In case errors are thrown the behavior is implementation specific. The error might get logged to stderr, or via other mechanisms that are implementations specific.
is a function that should be called with a callback for signaling the result once it is ready
async for the simpler variant.
A generalized version of bracket which uses ExitCase to distinguish between different exit cases when releasing the acquired resource.
A generalized version of bracket which uses ExitCase to distinguish between different exit cases when releasing the acquired resource.
is an action that "acquires" some expensive resource, that needs to be used and then discarded
is the action that uses the newly allocated resource and that will provide the final result
is the action that's supposed to release the
allocated resource after use
is done, by observing
and acting on its exit condition
Suspends the evaluation of an F
reference.
Suspends the evaluation of an F
reference.
Equivalent to FlatMap.flatten
for pure expressions,
the purpose of this function is to suspend side effects
in F
.
Operation meant for specifying tasks with safe resource acquisition and release in the face of errors and interruption.
Operation meant for specifying tasks with safe resource acquisition and release in the face of errors and interruption.
This operation provides the equivalent of try/catch/finally
statements in mainstream imperative languages for resource
acquisition and release.
is an action that "acquires" some expensive resource, that needs to be used and then discarded
is the action that uses the newly allocated resource and that will provide the final result
is the action that's supposed to release the
allocated resource after use
is done, irregardless of
its exit condition
Lifts any by-name parameter into the F
context.
Lifts any by-name parameter into the F
context.
Equivalent to Applicative.pure
for pure expressions,
the purpose of this function is to suspend side effects
in F
.
Executes the given finalizer
when the source is finished,
either in success or in error, or if canceled.
Executes the given finalizer
when the source is finished,
either in success or in error, or if canceled.
This variant of guaranteeCase evaluates the given finalizer
regardless of how the source gets terminated:
This equivalence always holds:
F.guarantee(fa)(f) <-> F.bracket(F.unit)(_ => fa)(_ => f)
As best practice, it's not a good idea to release resources
via guaranteeCase
in polymorphic code. Prefer bracket
for the acquisition and release of resources.
bracket for the more general operation
guaranteeCase for the version that can discriminate between termination conditions
Executes the given finalizer
when the source is finished,
either in success or in error, or if canceled, allowing
for differentiating between exit conditions.
Executes the given finalizer
when the source is finished,
either in success or in error, or if canceled, allowing
for differentiating between exit conditions.
This variant of guarantee injects an ExitCase in the provided function, allowing one to make a difference between:
This equivalence always holds:
F.guaranteeCase(fa)(f) <-> F.bracketCase(F.unit)(_ => fa)((_, e) => f(e))
As best practice, it's not a good idea to release resources
via guaranteeCase
in polymorphic code. Prefer bracketCase
for the acquisition and release of resources.
bracketCase for the more general operation
guarantee for the simpler version
Inherited from LiftIO, defines a conversion from IO
in terms of the Async
type class.
Inherited from LiftIO, defines a conversion from IO
in terms of the Async
type class.
N.B. expressing this conversion in terms of Async
and its
capabilities means that the resulting F
is not cancelable.
Concurrent then overrides this with an implementation
that is.
To access this implementation as a standalone function, you can use Async.liftIO (on the object companion).
Returns a non-terminating F[_]
, that never completes
with a result, being equivalent to async(_ => ())
Operation meant for ensuring a given task continues execution even when interrupted.
Operation meant for ensuring a given task continues execution even when interrupted.
(Since version 1.0.0-RC2) Use *> or productR instead.
(Since version 1.0.0-RC2) Use productREval instead.
(Since version 1.0.0-RC2) Use <* or productL instead.
(Since version 1.0.0-RC2) Use productLEval instead.
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:
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'sFuture#onComplete
: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:
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:
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:
N.B. such asynchronous processes are not cancelable. See the Concurrent alternative for that.