sealed abstract class IO[+A] extends IOPlatform[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:
- 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 ofMonadError
) 3. can be canceled, but note this capability relies on the user to provide cancelation 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.pure(a + b) flatMap { b2 => if (n > 0) fib(n - 1, b, b2) else IO.pure(a) }
- Source
- IO.scala
- Alphabetic
- By Inheritance
- IO
- IOPlatform
- AnyRef
- Any
- Hide All
- Show All
- Public
- All
Value Members
-
final
def
!=(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
final
def
##(): Int
- Definition Classes
- AnyRef → Any
-
def
&>[B](that: IO[B]): IO[B]
Runs this IO and the parameter in parallel.
Runs this IO and the parameter in parallel.
Failure in either of the IOs will cancel the other one. If the whole computation is canceled, both actions are also canceled.
-
def
*>[B](that: IO[B]): IO[B]
Runs the current IO, then runs the parameter, keeping its result.
Runs the current IO, then runs the parameter, keeping its result. The result of the first action is ignored. If the source fails, the other action won't run.
-
def
<&[B](that: IO[B]): IO[A]
Like &>, but keeps the result of the source
-
def
<*[B](that: IO[B]): IO[A]
Like *>, but keeps the result of the source.
-
final
def
==(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
- def >>[B](that: ⇒ IO[B]): IO[B]
-
def
as[B](b: B): IO[B]
Replaces the result of this IO with the given value.
-
final
def
asInstanceOf[T0]: T0
- Definition Classes
- Any
-
def
attempt: IO[Either[Throwable, A]]
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 intry
/catch
, being the inverse ofIO.raiseError
. Thus:IO.raiseError(ex).attempt.unsafeRunAsync === Left(ex)
- See also
-
def
background: ResourceIO[IO[OutcomeIO[A]]]
Returns a resource that will start execution of this IO in the background.
Returns a resource that will start execution of this IO in the background.
In case the resource is closed while this IO is still running (e.g. due to a failure in
use
), the background action will be canceled.- See also
cats.effect.kernel.GenSpawn#background for the generic version.
- def backgroundOn(ec: ExecutionContext): ResourceIO[IO[OutcomeIO[A]]]
- def both[B](that: IO[B]): IO[(A, B)]
- def bothOutcome[B](that: IO[B]): IO[(OutcomeIO[A], OutcomeIO[B])]
-
def
bracket[B](use: (A) ⇒ IO[B])(release: (A) ⇒ IO[Unit]): IO[B]
Returns an
IO
action that treats the source task as the acquisition of a resource, which is then exploited by theuse
function and thenreleased
.Returns an
IO
action that treats the source task as the acquisition of a resource, which is then exploited by theuse
function and thenreleased
.The
bracket
operation is the equivalent of thetry {} 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 cancelation.If an exception is raised, then
bracket
will re-raise the exception after performing therelease
. If the resulting task gets canceled, thenbracket
will still perform therelease
, 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 cancelation the underlying implementation cannot guarantee that the computation described by
use
doesn't end up executed concurrently with the computation fromrelease
. In the example above that ugly Java loop might end up reading from aBufferedReader
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 cancelation.
NOTE on error handling: in case both the
release
function and theuse
function throws, the error raised byrelease
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
"Bar"
, while the"Foo"
error gets reported on a side-channel. This is consistent with the behaviortry {} finally {}
.- use
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- release
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
- See also
-
def
bracketCase[B](use: (A) ⇒ IO[B])(release: (A, OutcomeIO[B]) ⇒ IO[Unit]): IO[B]
Returns a new
IO
task that treats the source task as the acquisition of a resource, which is then exploited by theuse
function and thenreleased
, with the possibility of distinguishing between normal termination and cancelation, 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 theuse
function and thenreleased
, with the possibility of distinguishing between normal termination and cancelation, such that an appropriate release of resources can be executed.The
bracketCase
operation is the equivalent oftry {} 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 cancelation.In comparison with the simpler bracket version, this one allows the caller to differentiate between normal termination, termination in error and cancelation via an Outcome parameter.
- use
is a function that evaluates the resource yielded by the source, yielding a result that will get generated by this function on evaluation
- release
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 release, along with the result ofuse
(cancelation, error or successful result)
- See also
-
def
clone(): AnyRef
- Attributes
- protected[lang]
- Definition Classes
- AnyRef
- Annotations
- @throws( ... ) @native()
-
def
delayBy(duration: FiniteDuration): IO[A]
Returns an IO that will delay the execution of the source by the given duration.
-
final
def
eq(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
-
def
equals(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
- def evalOn(ec: ExecutionContext): IO[A]
-
def
finalize(): Unit
- Attributes
- protected[lang]
- Definition Classes
- AnyRef
- Annotations
- @throws( classOf[java.lang.Throwable] )
-
def
flatMap[B](f: (A) ⇒ IO[B]): IO[B]
Monadic bind on
IO
, used for sequentially composing twoIO
actions, where the value produced by the firstIO
is passed as input to a function producing the secondIO
action.Monadic bind on
IO
, used for sequentially composing twoIO
actions, where the value produced by the firstIO
is passed as input to a function producing the secondIO
action.Due to this operation's signature,
flatMap
forces a data dependency between twoIO
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 andIO
references would never terminate on evaluation. - def flatten[B](implicit ev: <:<[A, IO[B]]): IO[B]
- def foreverM: IO[Nothing]
-
final
def
getClass(): Class[_]
- Definition Classes
- AnyRef → Any
- Annotations
- @native()
-
def
guarantee(finalizer: IO[Unit]): IO[A]
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:- normal completion
- completion in error
- cancelation
This equivalence always holds:
io.guarantee(f) <-> IO.unit.bracket(_ => io)(_ => f)
- See also
guaranteeCase for the version that can discriminate between termination conditions
-
def
guaranteeCase(finalizer: (OutcomeIO[A]) ⇒ IO[Unit]): IO[A]
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 Outcome in the provided function, allowing one to make a difference between:
- normal completion
- completion in error
- cancelation
This equivalence always holds:
io.guaranteeCase(f) <-> IO.unit.bracketCase(_ => io)((_, e) => f(e))
- See also
guarantee for the simpler version
-
def
handleErrorWith[B >: A](f: (Throwable) ⇒ IO[B]): IO[B]
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
. -
def
hashCode(): Int
- Definition Classes
- AnyRef → Any
- Annotations
- @native()
- def ifM[B](ifTrue: ⇒ IO[B], ifFalse: ⇒ IO[B])(implicit ev: <:<[A, Boolean]): IO[B]
-
final
def
isInstanceOf[T0]: Boolean
- Definition Classes
- Any
- def iterateUntil(p: (A) ⇒ Boolean): IO[A]
- def iterateWhile(p: (A) ⇒ Boolean): IO[A]
-
def
map[B](f: (A) ⇒ B): IO[B]
Functor map on
IO
.Functor map on
IO
. Given a mapping function, it transforms the value produced by the source, while keeping theIO
context.Any exceptions thrown within the function will be caught and sequenced into the
IO
. Due to the nature of asynchronous processes, without catching and handling exceptions, failures would be completely silent andIO
references would never terminate on evaluation. - def memoize: IO[IO[A]]
-
final
def
ne(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
-
final
def
notify(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native()
-
final
def
notifyAll(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native()
- def onCancel(fin: IO[Unit]): IO[A]
- def onError(f: (Throwable) ⇒ IO[Unit]): IO[A]
-
def
option: IO[Option[A]]
Replaces failures in this IO with an empty Option.
- def product[B](that: IO[B]): IO[(A, B)]
- def productL[B](that: IO[B]): IO[A]
- def productR[B](that: IO[B]): IO[B]
- def race[B](that: IO[B]): IO[Either[A, B]]
- def raceOutcome[B](that: IO[B]): IO[Either[OutcomeIO[A], OutcomeIO[B]]]
- def racePair[B](that: IO[B]): IO[Either[(OutcomeIO[A], FiberIO[B]), (FiberIO[A], OutcomeIO[B])]]
-
def
redeem[B](recover: (Throwable) ⇒ B, map: (A) ⇒ B): IO[B]
Returns a new value that transforms the result of the source, given the
recover
ormap
functions, which get executed depending on whether the result ends in error or if it is successful.Returns a new value that transforms the result of the source, given the
recover
ormap
functions, which get executed depending on whether the result ends in error or if it is successful.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
subsumeshandleError
because:io.redeem(fe, id) <-> io.handleError(fe)
- recover
is a function used for error recover in case the source ends in error
- map
is a function used for mapping the result of the source in case it ends in success
-
def
redeemWith[B](recover: (Throwable) ⇒ IO[B], bind: (A) ⇒ IO[B]): IO[B]
Returns a new value that transforms the result of the source, given the
recover
orbind
functions, which get executed depending on whether the result ends in error or if it is successful.Returns a new value that transforms the result of the source, given the
recover
orbind
functions, which get executed depending on whether the result ends in error or if it is successful.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
subsumeshandleErrorWith
because:io.redeemWith(fe, F.pure) <-> io.handleErrorWith(fe)
Usage of
redeemWith
also subsumes flatMap because:io.redeemWith(F.raiseError, fs) <-> io.flatMap(fs)
- recover
is the function that gets called to recover the source in case of error
- bind
is the function that gets to transform the source in case of success
-
def
start: IO[FiberIO[A]]
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 cancelation):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
(viacats.Parallel
) is still recommended because of behavior on error and cancelation — 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.Also see background for a safer alternative.
- def startOn(ec: ExecutionContext): IO[FiberIO[A]]
-
final
def
synchronized[T0](arg0: ⇒ T0): T0
- Definition Classes
- AnyRef
- def timed: IO[(FiniteDuration, A)]
-
def
timeout[A2 >: A](duration: FiniteDuration): IO[A2]
Returns an IO that either completes with the result of the source within the specified time
duration
or otherwise raises aTimeoutException
.Returns an IO that either completes with the result of the source within the specified time
duration
or otherwise raises aTimeoutException
.The source is canceled in the event that it takes longer than the specified time duration to complete.
- duration
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
-
def
timeoutTo[A2 >: A](duration: FiniteDuration, fallback: IO[A2]): IO[A2]
Returns an IO that either completes with the result of the source within the specified time
duration
or otherwise evaluates thefallback
.Returns an IO that either completes with the result of the source within the specified time
duration
or otherwise evaluates thefallback
.The source is canceled in the event that it takes longer than the
FiniteDuration
to complete, the evaluation of the fallback happening immediately after that.- duration
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- fallback
is the task evaluated after the duration has passed and the source canceled
-
def
to[F[_]](implicit F: LiftIO[F]): F[A]
Converts the source
IO
into anyF
type that implements the LiftIO type class. -
def
toString(): String
- Definition Classes
- IO → AnyRef → Any
-
def
uncancelable: IO[A]
Makes the source
IO
uninterruptible such that a cats.effect.kernel.Fiber#cancel signal has no effect. -
def
unsafeRunAndForget()(implicit runtime: IORuntime): Unit
Triggers the evaluation of the source and any suspended side effects therein, but ignores the result.
Triggers the evaluation of the source and any suspended side effects therein, but ignores the result.
This operation is similar to unsafeRunAsync, in that the evaluation can happen asynchronously, except no callback is required and therefore the result is ignored.
Note that errors still get logged (via IO's internal logger), because errors being thrown should never be totally silent.
-
def
unsafeRunAsync(cb: (Either[Throwable, A]) ⇒ Unit)(implicit runtime: IORuntime): Unit
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.
- def unsafeRunAsyncOutcome(cb: (Outcome[Id, Throwable, A]) ⇒ Unit)(implicit runtime: IORuntime): Unit
-
def
unsafeRunCancelable()(implicit runtime: IORuntime): () ⇒ Future[Unit]
Evaluates the effect, returning a cancelation token that can be used to cancel it.
Evaluates the effect, returning a cancelation token that can be used to cancel it.
This is similar to
unsafeRunAsync
in that it evaluates theIO
as a side effect in a non-blocking fashion, but uses aFuture
rather than an explicit callback. This function should really only be used if interoperating with code which uses Scala futures.- See also
-
final
def
unsafeRunSync()(implicit runtime: IORuntime): A
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. 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.
- Definition Classes
- IOPlatform
-
final
def
unsafeRunTimed(limit: FiniteDuration)(implicit runtime: IORuntime): Option[A]
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. As soon as an async blocking limit is hit, evaluation immediately aborts andNone
is returned. Note that this does not run finalizers, which makes it quite different (and less safe) than other mechanisms for limiting evaluation time.val program: IO[A] = ... program.timeout(5.seconds).unsafeRunSync() program.unsafeRunTimed(5.seconds)
The first line will run
program
for at most five seconds, interrupt the calculation, and run the finalizers for as long as they need to complete. The second line will runprogram
for at most five seconds and then immediately release the latch, without interruptingprogram
's ongoing execution.In other words, this function probably doesn't do what you think it does, and you probably don't want to use it outside of tests.
- Definition Classes
- IOPlatform
- See also
timeout for pure and safe version
-
final
def
unsafeToCompletableFuture()(implicit runtime: IORuntime): CompletableFuture[A]
- Definition Classes
- IOPlatform
-
def
unsafeToFuture()(implicit runtime: IORuntime): Future[A]
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 theIO
as a side effect in a non-blocking fashion, but uses aFuture
rather than an explicit callback. This function should really only be used if interoperating with code which uses Scala futures.- See also
-
def
unsafeToFutureCancelable()(implicit runtime: IORuntime): (Future[A], () ⇒ Future[Unit])
Evaluates the effect and produces the result in a
Future
, along with a cancelation token that can be used to cancel the original effect.Evaluates the effect and produces the result in a
Future
, along with a cancelation token that can be used to cancel the original effect.This is similar to
unsafeRunAsync
in that it evaluates theIO
as a side effect in a non-blocking fashion, but uses aFuture
rather than an explicit callback. This function should really only be used if interoperating with code which uses Scala futures.- See also
- def untilM[G[_], B >: A](cond: ⇒ IO[Boolean])(implicit arg0: Alternative[G]): IO[G[B]]
- def untilM_(cond: ⇒ IO[Boolean]): IO[Unit]
-
def
void: IO[Unit]
Ignores the result of this IO.
-
final
def
wait(): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... )
-
final
def
wait(arg0: Long, arg1: Int): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... )
-
final
def
wait(arg0: Long): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... ) @native()
- def whileM[G[_], B >: A](p: IO[Boolean])(implicit arg0: Alternative[G]): IO[G[B]]
- def whileM_(p: IO[Boolean]): IO[Unit]