What is Zio?
ZIO is a zero-dependency library for asynchronous and concurrent programming that is based on pure functional programming. It is ideal for mid to large-scale projects that require a lot of concurrency and speed.
Dependency
Include ZIO in your project by adding the following to your build.sbt
file:
libraryDependencies += "dev.zio" %% "zio" % "1.0.12"
Scala 3 and Scala 2.13 will both work with no changes to the code. Nothing else will be required.
Data Types
ZIO is a value that might fail or succeed. It requires three parameters: ZIO[R, E, A]
ZIO[R, E, A]:-
R -> Environment type, Representing the dependencies the effect needs to execute.
E -> Exception type, When an effect fails, It will be needing a type.
A -> Success type, When an effect succeeds, It will require a type.
A value of type ZIO[R, E, A]
is like an effectful version of the following function type:
R => Either[E, A]
UIO
UIO[A] is a type alias of ZIO[Any, Nothing, A] which represents an effect without exception but it can succeed with type A.
ZIO[Any, Nothing, Int] -> UIO[Int]
Instead of ZIO[Any, Nothing, Int], we can use UIO[Int]
URIO
URIO[R, A] is a type alias of ZIO[R, Nothing, A
] which represents an effect that requires an R
and cannot fail, but can succeed with type A
.
ZIO[Console, Nothing, Int] -> URIO[Console, Int]
Instead of ZIO[Console, Nothing, Int], we can use URIO[Console, Int]
Task
Task[A]
is a type alias of ZIO[Any, Throwable, A]
which represents an effect that has no requirements, and may fail with a Throwable
value, or succeed with an A
.
ZIO[Any, Throwable, Int] -> Task[Int]
Instead of ZIO[Any, Throwable, Int], we can use Task[Int]
RIO
RIO[R, A]
is a type alias for ZIO[R, Throwable, A]
, which represents an effect that requires an R
, and may fail with a Throwable
value, or succeed with an A
.
So the RIO
just equal to ZIO
which its error channel is Throwable
.
ZIO[Console, Throwable, Int] -> RIO[Console, Int]
Instead of ZIO[Console, Throwable, Int], we can use RIO[Console, Int]
IO
IO[E, A]
is a type alias for ZIO[Any, E, A]
which represents an effect that has no requirements, and may fail with an E
, or succeed with an A
.
ZIO[Any, Throwable, Int] -> IO[Throwable, Int]
Instead of ZIO[Any, Throwable, Int], we can use IO[Throwable, Int]
Fibers
ZIO has low-level support for concurrency using fibers. While fibers are very powerful, they are low-level. To improve productivity, It provides high-level operations built on fibers. Its runtime schedules fibers and they will mutually yield to each other, allowing for multitasking even in a single-threaded.
Every effect in ZIO is carried out via a fiber. If you did not create the fiber, it was generated by an operation you are running (whether concurrent or simultaneous) or by the its runtime system.
Effects running on Single Fiber Synchronously

Effects running on Multiple Fibers Asynchronously



As you can see in the above code snippet task1, task2, task3 are running on 3 different fibers which are namely [zio-default-async-2], [zio-default-async-3], [zio-default-async-1]. Whereas in the first code snippet we can see that all 3 tasks are running on a single fiber [zio-default-async-1].
Whenever we need to start a fiber, we have to fork
an effect and it gives us a fiber. You can see we use the fork method to create a new fiber that is working asynchronously.
task1.debug(printThread).fork
Conclusion
Thank you guys for making it to the end of the blog I hope you gained some knowledge about Effectful programming.
Reference
For more detailed information you can use this link: https://zio.dev/
My previous blog on pure function: https://blog.knoldus.com/what-is-pure-function-functional-programming-in-scala/