Class/Object

cats.effect

IO

Related Docs: object IO | package effect

Permalink

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(b2)
  }
Source
IO.scala
Linear Supertypes
IOBinaryCompat[A], AnyRef, Any
Ordering
  1. Alphabetic
  2. By Inheritance
Inherited
  1. IO
  2. IOBinaryCompat
  3. AnyRef
  4. Any
  1. Hide All
  2. Show All
Visibility
  1. Public
  2. All

Value Members

  1. final def !=(arg0: Any): Boolean

    Permalink
    Definition Classes
    AnyRef → Any
  2. final def ##(): Int

    Permalink
    Definition Classes
    AnyRef → Any
  3. final def ==(arg0: Any): Boolean

    Permalink
    Definition Classes
    AnyRef → Any
  4. final def asInstanceOf[T0]: T0

    Permalink
    Definition Classes
    Any
  5. def attempt: IO[Either[Throwable, A]]

    Permalink

    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)
    See also

    IO.raiseError

  6. final def bracket[B](use: (A) ⇒ IO[B])(release: (A) ⇒ IO[Unit]): IO[B]

    Permalink

    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.

    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

    bracketCase

  7. def bracketCase[B](use: (A) ⇒ IO[B])(release: (A, ExitCase[Throwable]) ⇒ IO[Unit]): IO[B]

    Permalink

    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.

    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 that needs release, along with the result of use (cancellation, error or successful result)

    See also

    bracket

  8. def clone(): AnyRef

    Permalink
    Attributes
    protected[java.lang]
    Definition Classes
    AnyRef
    Annotations
    @throws( ... )
  9. final def eq(arg0: AnyRef): Boolean

    Permalink
    Definition Classes
    AnyRef
  10. def equals(arg0: Any): Boolean

    Permalink
    Definition Classes
    AnyRef → Any
  11. def finalize(): Unit

    Permalink
    Attributes
    protected[java.lang]
    Definition Classes
    AnyRef
    Annotations
    @throws( classOf[java.lang.Throwable] )
  12. final def flatMap[B](f: (A) ⇒ IO[B]): IO[B]

    Permalink

    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.

  13. final def getClass(): Class[_]

    Permalink
    Definition Classes
    AnyRef → Any
  14. def guarantee(finalizer: IO[Unit]): IO[A]

    Permalink

    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)

    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.

    See also

    bracket for the more general operation

    guaranteeCase for the version that can discriminate between termination conditions

  15. def guaranteeCase(finalizer: (ExitCase[Throwable]) ⇒ IO[Unit]): IO[A]

    Permalink

    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:

    • normal completion
    • completion in error
    • cancelation

    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.

    See also

    bracketCase for the more general operation

    guarantee for the simpler version

  16. def handleErrorWith[AA >: A](f: (Throwable) ⇒ IO[AA]): IO[AA]

    Permalink

    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.

  17. def hashCode(): Int

    Permalink
    Definition Classes
    AnyRef → Any
  18. final def isInstanceOf[T0]: Boolean

    Permalink
    Definition Classes
    Any
  19. final def map[B](f: (A) ⇒ B): IO[B]

    Permalink

    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.

  20. final def ne(arg0: AnyRef): Boolean

    Permalink
    Definition Classes
    AnyRef
  21. final def notify(): Unit

    Permalink
    Definition Classes
    AnyRef
  22. final def notifyAll(): Unit

    Permalink
    Definition Classes
    AnyRef
  23. final def onCancelRaiseError(e: Throwable): IO[A]

    Permalink

    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.

  24. def redeem[B](recover: (Throwable) ⇒ B, map: (A) ⇒ B): IO[B]

    Permalink

    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)
    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

  25. def redeemWith[B](recover: (Throwable) ⇒ IO[B], bind: (A) ⇒ IO[B]): IO[B]

    Permalink

    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)
    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

  26. final def runAsync(cb: (Either[Throwable, A]) ⇒ IO[Unit]): IO[Unit]

    Permalink

    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
    returns

    an IO value that upon evaluation will execute the source, but will not wait for its completion

    See also

    runCancelable for the version that gives you a cancelable token that can be used to send a cancel signal

  27. final def runCancelable(cb: (Either[Throwable, A]) ⇒ IO[Unit]): IO[IO[Unit]]

    Permalink

    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
    returns

    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

    See also

    runAsync for the simple, uninterruptible version

  28. final def runSyncStep: IO[Either[IO[A], A]]

    Permalink
  29. final def start(implicit timer: Timer[IO]): IO[Fiber[IO, A]]

    Permalink

    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.

  30. final def synchronized[T0](arg0: ⇒ T0): T0

    Permalink
    Definition Classes
    AnyRef
  31. final def timeout(duration: FiniteDuration)(implicit timer: Timer[IO]): IO[A]

    Permalink

    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.

    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

  32. final def timeoutTo[A2 >: A](duration: FiniteDuration, fallback: IO[A2])(implicit timer: Timer[IO]): IO[A2]

    Permalink

    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.

    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

  33. final def to[F[_]](implicit F: LiftIO[F]): F[A]

    Permalink

    Converts the source IO into any F type that implements the LiftIO type class.

  34. def toString(): String

    Permalink
    Definition Classes
    IO → AnyRef → Any
  35. final def uncancelable: IO[A]

    Permalink

    Makes the source IO uninterruptible such that a Fiber.cancel signal has no effect.

  36. final def unsafeRunAsync(cb: (Either[Throwable, A]) ⇒ Unit): Unit

    Permalink

    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.

  37. final def unsafeRunCancelable(cb: (Either[Throwable, A]) ⇒ Unit): () ⇒ Unit

    Permalink

    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.

    returns

    an side-effectful function that, when executed, sends a cancellation reference to IO's run-loop implementation, having the potential to interrupt it.

  38. final def unsafeRunSync(): A

    Permalink

    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.

  39. final def unsafeRunTimed(limit: Duration): Option[A]

    Permalink

    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).

    See also

    timeout for pure and safe version

    unsafeRunSync

  40. final def unsafeToFuture(): Future[A]

    Permalink

    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.

    See also

    IO.fromFuture

  41. final def wait(): Unit

    Permalink
    Definition Classes
    AnyRef
    Annotations
    @throws( ... )
  42. final def wait(arg0: Long, arg1: Int): Unit

    Permalink
    Definition Classes
    AnyRef
    Annotations
    @throws( ... )
  43. final def wait(arg0: Long): Unit

    Permalink
    Definition Classes
    AnyRef
    Annotations
    @throws( ... )

Inherited from IOBinaryCompat[A]

Inherited from AnyRef

Inherited from Any

Ungrouped