Adam Fraser – Solving the Dependency Injection Problem with ZIO

Adam Fraser

Adam Fraser

Adam Fraser is a core contributor to ZIO, a library for asynchronous and concurrent programming in functional Scala. He is the co-author of ZIO Test and worked closely with John De Goes in the development of the new encoding for ZIO’s environment type.

Solving the Dependency Injection Problem with ZIO

ZIO is a library for high performance asynchronous and concurrent programming in Scala. ZIO leverages the power of pure functional programming while taking advantage of the unique features of Scala, such as subtyping and variance, to deliver an unprecedented developer experience.

One of ZIO’s key innovations is its environment type, which builds in a “reader monad” effect without the poor ergonomics and performance issues of traditional monad transformers. This allows directly representing an application’s required dependencies in its type signature. For example, a ZIO[Console, IOException, String] models an effect that requires a console capability and may either fail with an IOException or succeed with a String. By taking advantage of Scala’s support for contravariance environmental requirements compose naturally. Combining an effect that requires a Console capability with an effect that requires a Random capability automatically results in an effect that requires both a Console and a Random capability, with excellent type inference.

This allows passing required services throughout an application in an extremely straightforward and ergonomic way. However, in previous versions of ZIO building and modifying bundles of services was not as easy, often involving significant boilerplate.

ZIO’s latest release features a completely new approach to building environments based on ZLayer, a “recipe” for building bundles of dependencies backed by a type level mapping from dependencies to services that implement those dependencies. This provides an extremely natural way to build dependency graphs, with each layer representing an “arrow” in the dependency graph. Layers are also very powerful, supporting features including:

  • Partial provision of services
  • Local modification or replacement of services
  • Services that require effects to create and may fail
  • Services that require finalization with strong guarantees about execution of finalizers regardless of how a program is terminated
  • Automatic parallelization and memoization of layers for maximum efficiency
  • Static guarantees that if a dependency graph compiles, it will run, and in particular that it contains no cyclic dependencies

Learn how to take advantage of ZIO and ZLayer to build your next program!

Scala Valentines #5, Part 2