Skip to main content
Version: ZIO 2.x (WIP)

Basic Operations

Mapping

You can map over the success channel of an effect by calling the ZIO#map method. This lets you transform the success values of effects.

import zio._

val succeeded: UIO[Int] = IO.succeed(21).map(_ * 2)

You can map over the error channel of an effect by calling the ZIO#mapError method. This lets you transform the failure values of effects.

val failed: IO[Exception, Unit] = 
IO.fail("No no!").mapError(msg => new Exception(msg))

Note that mapping over an effect's success or error channel does not change the success or failure of the effect, in the same way that mapping over an Either does not change whether the Either is Left or Right.

Chaining

You can execute two effects in sequence with the flatMap method, which requires that you pass a callback, which will receive the value of the first effect, and can return a second effect that depends on this value:

val sequenced = 
readLine.flatMap(input => printLine(s"You entered: $input"))

If the first effect fails, the callback passed to flatMap will never be invoked, and the composed effect returned by flatMap will also fail.

In any chain of effects, the first failure will short-circuit the whole chain, just like throwing an exception will prematurely exit a sequence of statements.

For Comprehensions

Because the ZIO data type supports both flatMap and map, you can use Scala's for comprehensions to build sequential effects:

val program = 
for {
_ <- printLine("Hello! What is your name?")
name <- readLine
_ <- printLine(s"Hello, ${name}, welcome to ZIO!")
} yield ()

For comprehensions provide a more procedural syntax for composing chains of effects.

Zipping

You can combine two effects into a single effect with the ZIO#zip method. The resulting effect succeeds with a tuple that contains the success values of both effects:

val zipped: UIO[(String, Int)] = 
ZIO.succeed("4").zip(ZIO.succeed(2))

Note that zip operates sequentially: the effect on the left side is executed before the effect on the right side.

In any zip operation, if either the left or right hand sides fail, then the composed effect will fail, because both values are required to construct the tuple.

Sometimes, when the success value of an effect is not useful (for example, it is Unit), it can be more convenient to use the ZIO#zipLeft or ZIO#zipRight functions, which first perform a zip, and then map over the tuple to discard one side or the other:

val zipRight1 = 
printLine("What is your name?").zipRight(readLine)

The zipRight and zipLeft functions have symbolic aliases, known as *> and <*, respectively. Some developers find these operators easier to read:

val zipRight2 = 
printLine("What is your name?") *>
readLine

Next Step

If you are comfortable with the basic operations on ZIO effects, then the next step is to learn about error handling.