# Effect Systems: Cats Effect and ZIO — Scala

Source: https://www.geekswithgeeks.com/en/scala/k-effects

> Understand why functional effect systems exist and how they model programs.

## Programs as values

**Effect systems** represent side effects (I/O, time, randomness, concurrency) as **values** describing what to do, which run only when the program is executed at the "end of the world". The two leading libraries are **Cats Effect** with its **`IO`** type (used with Cats, http4s, fs2 and Doobie) and **ZIO** with **`ZIO[R, E, A]`** (an environment, a typed error and a result). Both offer **lazy, referentially transparent** effects, so the same `IO` value can be run, retried or timed out repeatedly. Both provide **fibers**: lightweight green threads, so you can run hundreds of thousands of concurrent tasks, with **structured concurrency**, safe **cancellation** and **resource safety** (`Resource` or `ZIO.acquireRelease` guarantee cleanup). They also include retry and schedule combinators, queues, refs and streaming (fs2 and ZIO Streams). The trade-off is a learning curve and a different programming style. For many services, effect systems provide predictable concurrency and error handling; for simpler applications, Futures or plain synchronous code on virtual threads may be enough.

## The same workflow in Cats Effect and ZIO

Lazy descriptions of effects with timeouts, retries and parallelism.

```scala
// Cats Effect
import cats.effect.{IO, IOApp}
import cats.syntax.all.*
import scala.concurrent.duration.*

object PricingApp extends IOApp.Simple:
  def fetchPrice(sku: String): IO[Long] =
    IO.println(s"fetching $sku") *> IO.sleep(100.millis).as(4950L)

  val run: IO[Unit] =
    for
      prices <- List("pen", "ink", "pad").parTraverse(fetchPrice)        // run in parallel on fibers
      total  <- IO.pure(prices.sum)
      _      <- IO.println(s"total: $total")
    yield ()

  // retry and timeout are combinators on the description:
  val robust: IO[Long] = fetchPrice("pen").timeout(2.seconds).handleErrorWith(_ => IO.pure(0L))

// ZIO equivalent (in a separate file)
// import zio.*
// object PricingZio extends ZIOAppDefault:
//   def fetchPrice(sku: String): UIO[Long] = ZIO.succeed(4950L).delay(100.millis)
//   def run = ZIO.foreachPar(List("pen", "ink", "pad"))(fetchPrice)
//     .map(_.sum)
//     .flatMap(total => Console.printLine(s"total: $total"))
```

## A screenplay versus a live performance

An IO value is a screenplay: writing it does not make anything happen, and you can copy it, edit it or add "if an actor is late, retry the scene". Only when the director shouts action (the runtime) is it performed.

**Quiz:** What is a key difference between Cats Effect IO and a standard Future?

- [ ] IO cannot run concurrently
- [x] IO is a lazy description that runs only when executed and can be re-run, while a Future starts eagerly
- [ ] Future supports cancellation but IO does not
- [ ] There is no difference

*Answer:* IO is a lazy description that runs only when executed and can be re-run, while a Future starts eagerly. Effects are lazy and referentially transparent; Futures start immediately and memoise their result.
