Skip to main content
Version: 1.0.18

How to use ZIO Macros?

Scrapping the boilerplate with macrosโ€‹

Many libraries come together with usage best practices and repeatable code, ZIO is no different. Fortunately ZIO provides macros to perform these repetitive tasks for you. At the moment these are only available for Scala versions 2.x, however their equivalents for Dotty are on our roadmap.

Prerequisitesโ€‹

To enable macro expansion you need to setup your project:

  • for Scala >= 2.13 add compiler option
scalacOptions += "-Ymacro-annotations"
  • for Scala < 2.13 add macro paradise compiler plugin
compilerPlugin(("org.scalamacros" % "paradise" % "2.1.1") cross CrossVersion.full)

Capability accessorsโ€‹

Installationโ€‹

libraryDependencies += "dev.zio" %% "zio-macros" % "<zio-version>"

Descriptionโ€‹

The @accessible macro generates capability accessors into annotated module object.

import zio.{ Has, ZIO }
import zio.macros.accessible

@accessible
object AccountObserver {
trait Service {
def processEvent(event: AccountEvent): UIO[Unit]
}

// below will be autogenerated
def processEvent(event: AccountEvent) =
ZIO.accessM[Has[AccountObserver.Service]](_.get[Service].processEvent(event))
}

For normal values, a ZIO with Nothing on error channel is generated. If the code is throwing exceptions see @throwing below.

import zio.{ Has, ZIO }
import zio.macros.accessible

@accessible
object Module {
trait Service {
def pureMethod(v: Something): SomethingElse
}

// below will be autogenerated
def pureMethod(v: Something): ZIO[Service, Nothing, SomethingElse] =
ZIO.access[Has[Module.Service]](_.get[Service].pureMethod(v))
}

The @throwing annotation will mark impure methods. Using this annotation will request ZIO to push the error on the error channel.

import zio.{ Has, ZIO }
import zio.macros.accessible

@accessible
object Module {
trait Service {
@throwing
def impureMethod(v: Something): SomethingElse
}

// below will be autogenerated
def impureMethod(v: Something): ZIO[Service, Throwable, SomethingElse] =
ZIO.accessM[Has[Module.Service]](s => ZIO(s.get[Service].impureMethod(v)))
}

Note: the macro can only be applied to objects which contain a trait called Service.

Capability tagsโ€‹

Installationโ€‹

libraryDependencies += "dev.zio" %% "zio-test" % "<zio-version>"

Descriptionโ€‹

The @mockable[A] generates capability tags and mock layer into annotated object.

import zio.test.mock.mockable

@mockable[AccountObserver.Service]
object AccountObserverMock

Will result in:

import zio.{ Has, UIO, URLayer, ZLayer }
import zio.test.mock.{ Mock, Proxy }

object AccountObserverMock extends Mock[Has[AccountObserver.Service]] {

object ProcessEvent extends Effect[AccountEvent, Nothing, Unit]
object RunCommand extends Effect[Unit, Nothing, Unit]

val compose: URLayer[Has[Proxy], AccountObserver] =
ZLayer.fromServiceM { proxy =>
withRuntime.map { rts =>
new AccountObserver.Service {
def processEvent(event: AccountEvent) = proxy(ProcessEvent, event)
def runCommand: UIO[Unit] = proxy(RunCommand)
}
}
}
}

ZIO Chat

๐ŸŽ‰ Hey there, ZIO aficionado! ๐ŸŽ‰ Step into the ZIO wonderland with me as your guide. Whether you're a functional fanatic or just dipping your toes into the ZIO ecosystem, I'm here to make your journey smooth. Got ZIO questions? I've got answers! Let's navigate the ZIO universe together and unlock its infinite possibilities!