Materializes any sequenced exceptions into value space, where they may be handled.
Materializes any sequenced exceptions into value space, where they may be handled.
This is analogous to the catch
clause in try
/catch
, being
the inverse of IO.raiseError
. Thus:
IO.raiseError(ex).attempt.unsafeRunAsync === Left(ex)
Returns an IO
action that treats the source task as the
acquisition of a resource, which is then exploited by the use
function and then released
.
Returns an IO
action that treats the source task as the
acquisition of a resource, which is then exploited by the use
function and then released
.
The bracket
operation is the equivalent of the
try {} catch {} finally {}
statements from mainstream languages.
The bracket
operation installs the necessary exception handler
to release the resource in the event of an exception being raised
during the computation, or in case of cancellation.
If an exception is raised, then bracket
will re-raise the
exception after performing the release
. If the resulting
task gets canceled, then bracket
will still perform the
release
, but the yielded task will be non-terminating
(equivalent with IO.never).
Example:
import java.io._ def readFile(file: File): IO[String] = { // Opening a file handle for reading text val acquire = IO(new BufferedReader( new InputStreamReader(new FileInputStream(file), "utf-8") )) acquire.bracket { in => // Usage part IO { // Yes, ugly Java, non-FP loop; // side-effects are suspended though var line: String = null val buff = new StringBuilder() do { line = in.readLine() if (line != null) buff.append(line) } while (line != null) buff.toString() } } { in => // The release part IO(in.close()) } }
Note that in case of cancellation the underlying implementation
cannot guarantee that the computation described by use
doesn't
end up executed concurrently with the computation from
release
. In the example above that ugly Java loop might end up
reading from a BufferedReader
that is already closed due to the
task being canceled, thus triggering an error in the background
with nowhere to get signaled.
In this particular example, given that we are just reading from a file, it doesn't matter. But in other cases it might matter, as concurrency on top of the JVM when dealing with I/O might lead to corrupted data.
For those cases you might want to do synchronization (e.g. usage of locks and semaphores) and you might want to use bracketCase, the version that allows you to differentiate between normal termination and cancellation.
NOTE on error handling: one big difference versus
try/finally
statements is that, in case both the release
function and the use
function throws, the error raised by use
gets signaled.
For example:
IO("resource").bracket { _ => // use IO.raiseError(new RuntimeException("Foo")) } { _ => // release IO.raiseError(new RuntimeException("Bar")) }
In this case the error signaled downstream is "Foo"
, while the
"Bar"
error gets reported. This is consistent with the behavior
of Haskell's bracket
operation and NOT with try {} finally {}
from Scala, Java or JavaScript.
is a function that evaluates the resource yielded by
the source, yielding a result that will get generated by
the task returned by this bracket
function
is a function that gets called after use
terminates, either normally or in error, or if it gets
canceled, receiving as input the resource that needs to
be released
Returns a new IO
task that treats the source task as the
acquisition of a resource, which is then exploited by the use
function and then released
, with the possibility of
distinguishing between normal termination and cancellation, such
that an appropriate release of resources can be executed.
Returns a new IO
task that treats the source task as the
acquisition of a resource, which is then exploited by the use
function and then released
, with the possibility of
distinguishing between normal termination and cancellation, such
that an appropriate release of resources can be executed.
The bracketCase
operation is the equivalent of
try {} catch {} finally {}
statements from mainstream languages
when used for the acquisition and release of resources.
The bracketCase
operation installs the necessary exception handler
to release the resource in the event of an exception being raised
during the computation, or in case of cancellation.
In comparison with the simpler bracket version, this one allows the caller to differentiate between normal termination, termination in error and cancellation via an ExitCase parameter.
is a function that evaluates the resource yielded by the source, yielding a result that will get generated by this function on evaluation
is a function that gets called after use
terminates, either normally or in error, or if it gets
canceled, receiving as input the resource that needs that
needs release, along with the result of use
(cancellation, error or successful result)
Monadic bind on IO
, used for sequentially composing two IO
actions, where the value produced by the first IO
is passed as
input to a function producing the second IO
action.
Monadic bind on IO
, used for sequentially composing two IO
actions, where the value produced by the first IO
is passed as
input to a function producing the second IO
action.
Due to this operation's signature, flatMap
forces a data
dependency between two IO
actions, thus ensuring sequencing
(e.g. one action to be executed before another one).
Any exceptions thrown within the function will be caught and
sequenced into the IO
, because due to the nature of
asynchronous processes, without catching and handling exceptions,
failures would be completely silent and IO
references would
never terminate on evaluation.
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:
io.guarantee(f) <-> IO.unit.bracket(_ => io)(_ => 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:
io.guaranteeCase(f) <-> IO.unit.bracketCase(_ => io)((_, 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
Handle any error, potentially recovering from it, by mapping it to another
IO
value.
Handle any error, potentially recovering from it, by mapping it to another
IO
value.
Implements ApplicativeError.handleErrorWith
.
Functor map on IO
.
Functor map on IO
. Given a mapping functions, it transforms the
value produced by the source, while keeping the IO
context.
Any exceptions thrown within the function will be caught and
sequenced into the IO
, because due to the nature of
asynchronous processes, without catching and handling exceptions,
failures would be completely silent and IO
references would
never terminate on evaluation.
Returns a new IO
that mirrors the source task for normal termination,
but that triggers the given error on cancellation.
Returns a new IO
that mirrors the source task for normal termination,
but that triggers the given error on cancellation.
Normally tasks that are canceled become non-terminating.
This onCancelRaiseError
operator transforms a task that is
non-terminating on cancellation into one that yields an error,
thus equivalent with IO.raiseError.
Returns a new value that transforms the result of the source,
given the recover
or map
functions, which get executed depending
on whether the result is successful or if it ends in error.
Returns a new value that transforms the result of the source,
given the recover
or map
functions, which get executed depending
on whether the result is successful or if it ends in error.
This is an optimization on usage of attempt and map, this equivalence being true:
io.redeem(recover, map) <-> io.attempt.map(_.fold(recover, map))
Usage of redeem
subsumes handleError
because:
io.redeem(fe, id) <-> io.handleError(fe)
is a function used for error recover in case the source ends in error
is a function used for mapping the result of the source in case it ends in success
Returns a new value that transforms the result of the source,
given the recover
or bind
functions, which get executed depending
on whether the result is successful or if it ends in error.
Returns a new value that transforms the result of the source,
given the recover
or bind
functions, which get executed depending
on whether the result is successful or if it ends in error.
This is an optimization on usage of attempt and flatMap, this equivalence being available:
io.redeemWith(recover, bind) <-> io.attempt.flatMap(_.fold(recover, bind))
Usage of redeemWith
subsumes handleErrorWith
because:
io.redeemWith(fe, F.pure) <-> io.handleErrorWith(fe)
Usage of redeemWith
also subsumes flatMap because:
io.redeemWith(F.raiseError, fs) <-> io.flatMap(fs)
is the function that gets called to recover the source in case of error
is the function that gets to transform the source in case of success
Produces an IO
reference that should execute the source on
evaluation, without waiting for its result, being the safe
analogue to unsafeRunAsync.
Produces an IO
reference that should execute the source on
evaluation, without waiting for its result, being the safe
analogue to unsafeRunAsync.
This operation is isomorphic to unsafeRunAsync. What it does
is to let you describe asynchronous execution with a function
that stores off the results of the original IO
as a
side effect, thus avoiding the usage of impure callbacks or
eager evaluation.
The returned IO
is guaranteed to execute immediately,
and does not wait on any async action to complete, thus this
is safe to do, even on top of runtimes that cannot block threads
(e.g. JavaScript):
// Sample val source = IO.shift *> IO(1) // Describes execution val start = source.runAsync { case Left(e) => IO(e.printStackTrace()) case Right(_) => IO.unit } // Safe, because it does not block for the source to finish start.unsafeRunSync
an IO
value that upon evaluation will execute the source,
but will not wait for its completion
runCancelable for the version that gives you a cancelable token that can be used to send a cancel signal
Produces an IO
reference that should execute the source on evaluation,
without waiting for its result and return a cancelable token, being the
safe analogue to unsafeRunCancelable.
Produces an IO
reference that should execute the source on evaluation,
without waiting for its result and return a cancelable token, being the
safe analogue to unsafeRunCancelable.
This operation is isomorphic to unsafeRunCancelable. Just like runAsync, this operation avoids the usage of impure callbacks or eager evaluation.
The returned IO
boxes an IO[Unit]
that can be used to cancel the
running asynchronous computation (if the source can be canceled).
The returned IO
is guaranteed to execute immediately,
and does not wait on any async action to complete, thus this
is safe to do, even on top of runtimes that cannot block threads
(e.g. JavaScript):
val source: IO[Int] = ??? // Describes interruptible execution val start: IO[IO[Unit]] = source.runCancelable // Safe, because it does not block for the source to finish val cancel: IO[Unit] = start.unsafeRunSync // Safe, because cancellation only sends a signal, // but doesn't back-pressure on anything cancel.unsafeRunSync
an IO
value that upon evaluation will execute the source,
but will not wait for its completion, yielding a cancellation
token that can be used to cancel the async process
runAsync for the simple, uninterruptible version
Start execution of the source suspended in the IO
context.
Start execution of the source suspended in the IO
context.
This can be used for non-deterministic / concurrent execution.
The following code is more or less equivalent with parMap2
(minus the behavior on error handling and cancellation):
def par2[A, B](ioa: IO[A], iob: IO[B]): IO[(A, B)] = for { fa <- ioa.start fb <- iob.start a <- fa.join b <- fb.join } yield (a, b)
Note in such a case usage of parMapN
(via cats.Parallel
) is
still recommended because of behavior on error and cancellation —
consider in the example above what would happen if the first task
finishes in error. In that case the second task doesn't get canceled,
which creates a potential memory leak.
Returns an IO that either completes with the result of the source within
the specified time duration
or otherwise raises a TimeoutException
.
Returns an IO that either completes with the result of the source within
the specified time duration
or otherwise raises a TimeoutException
.
The source is cancelled in the event that it takes longer than the specified time duration to complete.
is the time span for which we wait for the source to
complete; in the event that the specified time has passed without
the source completing, a TimeoutException
is raised
Returns an IO that either completes with the result of the source within
the specified time duration
or otherwise evaluates the fallback
.
Returns an IO that either completes with the result of the source within
the specified time duration
or otherwise evaluates the fallback
.
The source is cancelled in the event that it takes longer than
the FiniteDuration
to complete, the evaluation of the fallback
happening immediately after that.
is the time span for which we wait for the source to
complete; in the event that the specified time has passed without
the source completing, the fallback
gets evaluated
is the task evaluated after the duration has passed and the source canceled
Converts the source IO
into any F
type that implements
the LiftIO type class.
Makes the source IO
uninterruptible such that a Fiber.cancel
signal has no effect.
Passes the result of the encapsulated effects to the given callback by running them as impure side effects.
Passes the result of the encapsulated effects to the given callback by running them as impure side effects.
Any exceptions raised within the effect will be passed to the
callback in the Either
. The callback will be invoked at most
*once*. Note that it is very possible to construct an IO which
never returns while still never blocking a thread, and attempting
to evaluate that IO with this method will result in a situation
where the callback is *never* invoked.
As the name says, this is an UNSAFE function as it is impure and performs side effects. You should ideally only call this function once, at the very end of your program.
Evaluates the source IO
, passing the result of the encapsulated
effects to the given callback.
Evaluates the source IO
, passing the result of the encapsulated
effects to the given callback.
As the name says, this is an UNSAFE function as it is impure and performs side effects. You should ideally only call this function once, at the very end of your program.
an side-effectful function that, when executed, sends a
cancellation reference to IO
's run-loop implementation,
having the potential to interrupt it.
Produces the result by running the encapsulated effects as impure side effects.
Produces the result by running the encapsulated effects as impure side effects.
If any component of the computation is asynchronous, the current
thread will block awaiting the results of the async computation.
On JavaScript, an exception will be thrown instead to avoid
generating a deadlock. By default, this blocking will be
unbounded. To limit the thread block to some fixed time, use
unsafeRunTimed
instead.
Any exceptions raised within the effect will be re-thrown during evaluation.
As the name says, this is an UNSAFE function as it is impure and performs side effects, not to mention blocking, throwing exceptions, and doing other things that are at odds with reasonable software. You should ideally only call this function *once*, at the very end of your program.
Similar to unsafeRunSync
, except with a bounded blocking
duration when awaiting asynchronous results.
Similar to unsafeRunSync
, except with a bounded blocking
duration when awaiting asynchronous results.
Please note that the limit
parameter does not limit the time of
the total computation, but rather acts as an upper bound on any
*individual* asynchronous block. Thus, if you pass a limit of 5
seconds
to an IO
consisting solely of synchronous actions, the
evaluation may take considerably longer than 5 seconds!
Furthermore, if you pass a limit of 5 seconds
to an IO
consisting of several asynchronous actions joined together,
evaluation may take up to n * 5 seconds
, where n
is the
number of joined async actions.
As soon as an async blocking limit is hit, evaluation
immediately aborts and None
is returned.
Please note that this function is intended for testing; it should never appear in your mainline production code! It is absolutely not an appropriate function to use if you want to implement timeouts, or anything similar. If you need that sort of functionality, you should be using a streaming library (like fs2 or Monix).
timeout for pure and safe version
Evaluates the effect and produces the result in a Future
.
Evaluates the effect and produces the result in a Future
.
This is similar to unsafeRunAsync
in that it evaluates the IO
as a side effect in a non-blocking fashion, but uses a Future
rather than an explicit callback. This function should really
only be used if interoperating with legacy code which uses Scala
futures.
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. AnIO
is a data structure that represents just a description of a side effectful computation.IO
can describe synchronous or asynchronous computations that:flatMap
chains get short-circuited (IO
implementing the algebra ofMonadError
)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:
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 itsflatMap
evaluation. This means that you can safely callflatMap
in a recursive function of arbitrary depth, without fear of blowing the stack.