SlideShare a Scribd company logo
ZLayer
A RAY TRACING EXERCISE
PIERANGELO CECCHETTO
Functional Rotterdam
04 Mar 2020
ZIO-101
ZIO[-R, +E, +A]
➡
R => IO[Either[E, A]]
➡
R => Either[E, A]
ZIO-101: PROGRAMS
val prg: ZIO[Console with Random, Nothing, Long] = for {
n <- random.nextLong // ZIO[Random, Nothing, Long]
_ <- console.putStrLn(s"Extracted $n ") // ZIO[Console, Nothing, Unit]
} yield n
val allNrs: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAll(List.fill(100)(prg))
val allNrsPar: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllPar(List.fill(100)(prg))
val allNrsParN: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllParN(10)(List.fill(100)(prg))
ZIO-101: PROGRAMS
▸ ZIO programs are values
val prg: ZIO[Console with Random, Nothing, Long] = for {
n <- random.nextLong // ZIO[Random, Nothing, Long]
_ <- console.putStrLn(s"Extracted $n ") // ZIO[Console, Nothing, Unit]
} yield n
val allNrs: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAll(List.fill(100)(prg))
val allNrsPar: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllPar(List.fill(100)(prg))
val allNrsParN: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllParN(10)(List.fill(100)(prg))
ZIO-101: PROGRAMS
▸ ZIO programs are values
▸ Concurrency based on fibers (green threads)
val prg: ZIO[Console with Random, Nothing, Long] = for {
n <- random.nextLong // ZIO[Random, Nothing, Long]
_ <- console.putStrLn(s"Extracted $n ") // ZIO[Console, Nothing, Unit]
} yield n
val allNrs: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAll(List.fill(100)(prg))
val allNrsPar: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllPar(List.fill(100)(prg))
val allNrsParN: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllParN(10)(List.fill(100)(prg))
ZIO-101: PROGRAMS
▸ ZIO programs are values
▸ Concurrency based on fibers (green threads)
val prg: ZIO[Console with Random, Nothing, Long] = for {
n <- random.nextLong // ZIO[Random, Nothing, Long]
_ <- console.putStrLn(s"Extracted $n ") // ZIO[Console, Nothing, Unit]
} yield n
val allNrs: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAll(List.fill(100)(prg))
val allNrsPar: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllPar(List.fill(100)(prg))
val allNrsParN: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllParN(10)(List.fill(100)(prg))
ZIO-101: PROGRAMS
▸ ZIO programs are values
▸ Concurrency based on fibers (green threads)
val prg: ZIO[Console with Random, Nothing, Long] = for {
n <- random.nextLong // ZIO[Random, Nothing, Long]
_ <- console.putStrLn(s"Extracted $n ") // ZIO[Console, Nothing, Unit]
} yield n
val allNrs: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAll(List.fill(100)(prg))
val allNrsPar: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllPar(List.fill(100)(prg))
val allNrsParN: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllParN(10)(List.fill(100)(prg))
ZIO-101: PROGRAMS
▸ ZIO programs are values
▸ Concurrency based on fibers (green threads)
val prg: ZIO[Console with Random, Nothing, Long] = for {
n <- random.nextLong // ZIO[Random, Nothing, Long]
_ <- console.putStrLn(s"Extracted $n ") // ZIO[Console, Nothing, Unit]
} yield n
val allNrs: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAll(List.fill(100)(prg))
val allNrsPar: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllPar(List.fill(100)(prg))
val allNrsParN: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllParN(10)(List.fill(100)(prg))
ZIO-101: PROGRAMS
▸ ZIO programs are values
▸ Concurrency based on fibers (green threads)
val prg: ZIO[Console with Random, Nothing, Long] = for {
n <- random.nextLong // ZIO[Random, Nothing, Long]
_ <- console.putStrLn(s"Extracted $n ") // ZIO[Console, Nothing, Unit]
} yield n
val allNrs: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAll(List.fill(100)(prg))
val allNrsPar: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllPar(List.fill(100)(prg))
val allNrsParN: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllParN(10)(List.fill(100)(prg))
ZIO-101: PROGRAMS
▸ ZIO programs are values
▸ Concurrency based on fibers (green threads)
val prg: ZIO[Console with Random, Nothing, Long] = for {
n <- random.nextLong // ZIO[Random, Nothing, Long]
_ <- console.putStrLn(s"Extracted $n ") // ZIO[Console, Nothing, Unit]
} yield n
val allNrs: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAll(List.fill(100)(prg))
val allNrsPar: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllPar(List.fill(100)(prg))
val allNrsParN: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllParN(10)(List.fill(100)(prg))
ZIO-101: R MEANS REQUIREMENT
val prg: ZIO[Console with Random, Nothing, Long] = ???
val autonomous: ZIO[Any, Nothing, Long] = ???
val getUserFromDb: ZIO[DBConnection, Nothing, User] = ???
ZIO-101: R MEANS REQUIREMENT
val prg: ZIO[Console with Random, Nothing, Long] = ???
val autonomous: ZIO[Any, Nothing, Long] = ???
val getUserFromDb: ZIO[DBConnection, Nothing, User] = ???
ZIO-101: R MEANS REQUIREMENT
val prg: ZIO[Console with Random, Nothing, Long] = ???
val autonomous: ZIO[Any, Nothing, Long] = ???
val getUserFromDb: ZIO[DBConnection, Nothing, User] = ???
ZIO-101: R MEANS REQUIREMENT
val prg: ZIO[Console with Random, Nothing, Long] = ???
val autonomous: ZIO[Any, Nothing, Long] = ???
val getUserFromDb: ZIO[DBConnection, Nothing, User] = ???
ZIO-101: REQUIREMENTS ELIMINATION
val getUserFromDb: ZIO[DBConnection, Nothing, User] = ???
val provided: ZIO[Any, Nothing, User] =
getUserFromDb.provide(DBConnection(...))
val user: User = Runtime.default.unsafeRun(provided)
ZIO-101: REQUIREMENTS ELIMINATION
val getUserFromDb: ZIO[DBConnection, Nothing, User] = ???
val provided: ZIO[Any, Nothing, User] =
getUserFromDb.provide(DBConnection(...))
val user: User = Runtime.default.unsafeRun(provided)
ZIO-101: REQUIREMENTS ELIMINATION
val getUserFromDb: ZIO[DBConnection, Nothing, User] = ???
val provided: ZIO[Any, Nothing, User] =
getUserFromDb.provide(DBConnection(...))
val user: User = Runtime.default.unsafeRun(provided)
ZIO-101: REQUIREMENTS ELIMINATION
val getUserFromDb: ZIO[DBConnection, Nothing, User] = ???
val provided: ZIO[Any, Nothing, User] =
getUserFromDb.provide(DBConnection(...))
val user: User = Runtime.default.unsafeRun(provided)
ZIO-101: MODULES
Example: a module to collect metrics1
type Metrics = Has[Metrics.Service]
object Metrics {
trait Service {
def inc(label: String): IO[Nothing, Unit]
}
//accessor method
def inc(label: String): ZIO[Metrics, Nothing, Unit] =
ZIO.accessM(_.get.inc(label))
}
}
1
ZIO 1.0.0-RC18
ZIO-101: MODULES
Example: a module to collect metrics1
type Metrics = Has[Metrics.Service]
object Metrics {
trait Service {
def inc(label: String): IO[Nothing, Unit]
}
//accessor method
def inc(label: String): ZIO[Metrics, Nothing, Unit] =
ZIO.accessM(_.get.inc(label))
}
}
1
ZIO 1.0.0-RC18
ZIO-101: MODULES
Example: a module to collect metrics1
type Metrics = Has[Metrics.Service]
object Metrics {
trait Service {
def inc(label: String): IO[Nothing, Unit]
}
//accessor method
def inc(label: String): ZIO[Metrics, Nothing, Unit] =
ZIO.accessM(_.get.inc(label))
}
}
1
ZIO 1.0.0-RC18
ZIO-101: MODULES
Example: a module for logging
type Log = Has[Log.Service]
object Log {
trait Service {
def info(s: String): IO[Nothing, Unit]
def error(s: String): IO[Nothing, Unit]
}
//accessor methods...
}
ZIO-101: MODULES
Write a program using existing modules
val prg: ZIO[Metrics with Log, Nothing, Unit] =
for {
_ <- Log.info("Hello")
_ <- Metrics.inc("salutation")
_ <- Log.info("Rotterdam")
_ <- Metrics.inc("subject")
} yield ()
ZIO-101: THE Has DATA TYPE
Has[A] is a dependency on a service of type A
val hasLog: Has[Log.Service] // type Log = Has[Log.Service]
val hasMetrics: Has[Metrics.Service] // type Metrics = Has[Metrics.Service]
val mix: Log with Metrics = hasLog ++ hasMetrics
//access each service
mix.get[Log.Service].info("Starting the application")
ZIO-101: THE Has DATA TYPE
Has[A] is a dependency on a service of type A
val hasLog: Has[Log.Service] // type Log = Has[Log.Service]
val hasMetrics: Has[Metrics.Service] // type Metrics = Has[Metrics.Service]
val mix: Log with Metrics = hasLog ++ hasMetrics
//access each service
mix.get[Log.Service].info("Starting the application")
ZIO-101: THE Has DATA TYPE
val mix: Log with Metrics = hasLog ++ hasMetrics
mix.get[Log.Service].info("Starting the application")
ZIO-101: THE Has DATA TYPE
val mix: Log with Metrics = hasLog ++ hasMetrics
mix.get[Log.Service].info("Starting the application")
▸ Is more powerful than trait mixins
ZIO-101: THE Has DATA TYPE
val mix: Log with Metrics = hasLog ++ hasMetrics
mix.get[Log.Service].info("Starting the application")
▸ Is more powerful than trait mixins
▸ Is backed by a heterogeneus map ServiceType -> Service
ZIO-101: THE Has DATA TYPE
val mix: Log with Metrics = hasLog ++ hasMetrics
mix.get[Log.Service].info("Starting the application")
▸ Is more powerful than trait mixins
▸ Is backed by a heterogeneus map ServiceType -> Service
▸ Can replace/update services
ZIO-101: ZLayer
ZLayer[-RIn, +E, +ROut <: Has[_]]
ZIO-101: ZLayer
ZLayer[-RIn, +E, +ROut <: Has[_]]
▸ A recipe to build an ROut
ZIO-101: ZLayer
ZLayer[-RIn, +E, +ROut <: Has[_]]
▸ A recipe to build an ROut
▸ Backed by ZManaged: safe acquire/release
ZIO-101: ZLayer
ZLayer[-RIn, +E, +ROut <: Has[_]]
▸ A recipe to build an ROut
▸ Backed by ZManaged: safe acquire/release
▸ type NoDeps[+E, +B <: Has[_]] =
ZLayer[Any, E, B]
ZIO-101: ZLayer
Construct from value
val layer: ZLayer.NoDeps[Nothing, UserRepo] =
ZLayer.succeed(new UserRepo.Service)
ZIO-101: ZLayer
Construct from function
val layer: ZLayer[Connection, Nothing, UserRepo] =
ZLayer.fromFunction { c: Connection =>
new UserRepo.Service
}
ZIO-101: ZLayer
Construct from effect
import java.sql.Connection
val e: ZIO[Connection, Error, UserRepo.Service]
val layer: ZLayer[Connection, Error, UserRepo] =
ZLayer.fromEffect(e)
ZIO-101: ZLayer
Construct from resources
import java.sql.Connection
val connectionLayer: ZLayer.NoDeps[Nothing, Has[Connection]] =
ZLayer.fromAcquireRelease(makeConnection) { c =>
UIO(c.close())
}
ZIO-101: ZLayer
Construct from other services
val usersLayer: ZLayer[UserRepo with UserValidation, Nothing, BusinessLogic] =
ZLayer.fromServices[UserRepo.Service, UserValidation.Service] {
(repoSvc, validSvc) =>
new BusinessLogic.Service {
// use repoSvc and validSvc
}
}
ZIO-101: ZLayer
Compose horizontally
(all inputs for all outputs)
val l1: ZLayer[Connection, Nothing, UserRepo]
val l2: ZLayer[Config, Nothing, AuthPolicy]
val hor: ZLayer[Connection with Config, Nothing, UserRepo with AuthPolicy] =
l1 ++ l2
ZIO-101: ZLayer
Compose vertically
(output of first for input of second)
val l1: ZLayer[Config, Nothing, Connection]
val l2: ZLayer[Connection, Nothing, UserRepo]
val ver: ZLayer[Config, Nothing, UserRepo] =
l1 >>> l2
ZIO-101: ZLayer
Create module instances
type UserRepo = Has[UserRepo.Service]
object UserRepo {
trait Service {
def getUser(userId: UserId): IO[DBError, Option[User]]
def createUser(user: User): IO[DBError, Unit]
}
val inMemory: ZLayer.NoDeps[Nothing, UserRepo] = ZLayer.succeed(
new Service {
/* impl */
}
)
val db: ZLayer[Connection, Nothing, UserRepo] = ZLayer.fromService { conn: Connection =>
new Service {
/* impl uses conn */
}
}
}
ZIO-101: ZLayer
Create module instances
type UserRepo = Has[UserRepo.Service]
object UserRepo {
trait Service {
def getUser(userId: UserId): IO[DBError, Option[User]]
def createUser(user: User): IO[DBError, Unit]
}
val inMemory: ZLayer.NoDeps[Nothing, UserRepo] = ZLayer.succeed(
new Service {
/* impl */
}
)
val db: ZLayer[Connection, Nothing, UserRepo] = ZLayer.fromService { conn: Connection =>
new Service {
/* impl uses conn */
}
}
}
ZIO-101: ZLayer
Create module instances
type UserRepo = Has[UserRepo.Service]
object UserRepo {
trait Service {
def getUser(userId: UserId): IO[DBError, Option[User]]
def createUser(user: User): IO[DBError, Unit]
}
val inMemory: ZLayer.NoDeps[Nothing, UserRepo] = ZLayer.succeed(
new Service {
/* impl */
}
)
val db: ZLayer[Connection, Nothing, UserRepo] = ZLayer.fromService { conn: Connection =>
new Service {
/* impl uses conn */
}
}
}
ZIO-101: ZLayer
Provide layers to programs
import zio.console.Console
val checkUser: ZIO[UserRepo with AuthPolicy with Console, Nothing, Boolean]
val liveLayer = UserRepo.inMemory ++ AuthPolicy.basicPolicy ++ Console.live
val full: ZIO[Any, Nothing, Boolean] = checkUser.provideLayer(
liveLayer
)
val partial: ZIO[Console, Nothing, Boolean] = checkUser.provideSomeLayer(
UserRepo.inMemory ++ AuthPolicy.basicPolicy
)
val updated: ZIO[Any, Nothing, Boolean] = checkUser.provideLayer(
liveLayer ++ UserRepo.postgres
)
ZIO-101: ZLayer
Provide layers to programs
import zio.console.Console
val checkUser: ZIO[UserRepo with AuthPolicy with Console, Nothing, Boolean]
val liveLayer = UserRepo.inMemory ++ AuthPolicy.basicPolicy ++ Console.live
val full: ZIO[Any, Nothing, Boolean] = checkUser.provideLayer(
liveLayer
)
val partial: ZIO[Console, Nothing, Boolean] = checkUser.provideSomeLayer(
UserRepo.inMemory ++ AuthPolicy.basicPolicy
)
val updated: ZIO[Any, Nothing, Boolean] = checkUser.provideLayer(
liveLayer ++ UserRepo.postgres
)
ZIO-101: ZLayer
Provide layers to programs
import zio.console.Console
val checkUser: ZIO[UserRepo with AuthPolicy with Console, Nothing, Boolean]
val liveLayer = UserRepo.inMemory ++ AuthPolicy.basicPolicy ++ Console.live
val full: ZIO[Any, Nothing, Boolean] = checkUser.provideLayer(
liveLayer
)
val partial: ZIO[Console, Nothing, Boolean] = checkUser.provideSomeLayer(
UserRepo.inMemory ++ AuthPolicy.basicPolicy
)
val updated: ZIO[Any, Nothing, Boolean] = checkUser.provideLayer(
liveLayer ++ UserRepo.postgres
)
ZIO-101: ZLayer
Provide layers to programs
import zio.console.Console
val checkUser: ZIO[UserRepo with AuthPolicy with Console, Nothing, Boolean]
val liveLayer = UserRepo.inMemory ++ AuthPolicy.basicPolicy ++ Console.live
val full: ZIO[Any, Nothing, Boolean] = checkUser.provideLayer(
liveLayer
)
val partial: ZIO[Console, Nothing, Boolean] = checkUser.provideSomeLayer(
UserRepo.inMemory ++ AuthPolicy.basicPolicy
)
val updated: ZIO[Any, Nothing, Boolean] = checkUser.provideLayer(
liveLayer ++ UserRepo.postgres
)
RAY TRACING
RAY TRACING
▸ World (spheres), light source, camera
RAY TRACING
▸ World (spheres), light source, camera
▸ Incident rays
RAY TRACING
▸ World (spheres), light source, camera
▸ Incident rays
▸ Reflected rays
RAY TRACING
▸ World (spheres), light source, camera
▸ Incident rays
▸ Reflected rays
▸ Discarded rays
▸ Canvas
RAY TRACING
▸ World (spheres), light source, camera
▸ Incident rays
▸ Reflected rays
▸ Discarded rays
▸ Canvas
▸ Colored pixels
RAY TRACING
▸ World (spheres), light source, camera
▸ Incident rays
▸ Reflected rays
▸ Discarded rays
▸ Canvas
▸ Colored pixels
RAY TRACING
Options:
RAY TRACING
Options:
1. Compute all the rays (and discard most of
them)
RAY TRACING
Options:
1. Compute all the rays (and discard most of
them)
2. Compute only the rays outgoing from the
camera through the canvas, and determine
how they behave on the surfaces
RAY
case class Ray(origin: Pt, direction: Vec) {
def positionAt(t: Double): Pt =
origin + (direction * t)
}
TRANSFORMATIONS MODULE
trait AT
type ATModule = Has[ATModule.Service]
object ATModule {
/* Service */
trait Service {
def applyTf(tf: AT, vec: Vec): ZIO[ATError, Vec]
def applyTf(tf: AT, pt: Pt): ZIO[ATError, Pt]
def compose(first: AT, second: AT): ZIO[ATError, AT]
}
def applyTf(tf: AT, vec: Vec): ZIO[ATModule, ATError, Vec] =
ZIO.accessM(_.aTModule.applyTf(tf, vec))
def applyTf(tf: AT, pt: Pt): ZIO[ATModule, ATError, Pt] =
ZIO.accessM(_.aTModule.applyTf(tf, pt))
def compose(first: AT, second: AT): ZIO[ATModule, ATError, AT] =
ZIO.accessM(_.aTModule.compose(first, second))
}
TRANSFORMATIONS MODULE
val rotatedPt =
for {
rotateX <- ATModule.rotateX(math.Pi / 2)
_ <- Log.info("rotated of π/2")
res <- ATModule.applyTf(rotateX, Pt(1, 1, 1))
} yield res
TRANSFORMATIONS MODULE
val rotatedPt: ZIO[ATModule with Log, ATError, Pt] =
for {
rotateX <- ATModule.rotateX(math.Pi / 2)
_ <- Log.info("rotated of π/2")
res <- ATModule.applyTf(rotateX, Pt(1, 1, 1))
} yield res
TRANSFORMATIONS MODULE - LIVE
val rotated: ZIO[ATModule, ATError, Vec] =
for {
rotateX <- ATModule.rotateX(math.Pi/2)
res <- ATModule.applyTf(rotateX, Pt(1, 1, 1))
} yield res
TRANSFORMATIONS MODULE - LIVE
val rotated: ZIO[ATModule, ATError, Vec] =
for {
rotateX <- ATModule.rotateX(math.Pi/2)
res <- ATModule.applyTf(rotateX, Pt(1, 1, 1))
} yield res
▸ Vec(x, y, z)
TRANSFORMATIONS MODULE - LIVE
val rotated: ZIO[ATModule, ATError, Vec] =
for {
rotateX <- ATModule.rotateX(math.Pi/2)
res <- ATModule.applyTf(rotateX, Pt(1, 1, 1))
} yield res
▸ Vec(x, y, z)
▸ Pt(x, y, z)⠀
TRANSFORMATIONS MODULE - LIVE
val rotated: ZIO[ATModule, ATError, Vec] =
for {
rotateX <- ATModule.rotateX(math.Pi/2)
res <- ATModule.applyTf(rotateX, Pt(1, 1, 1))
} yield res
▸ Vec(x, y, z)
▸ Pt(x, y, z)⠀
▸ ⠀
TRANSFORMATIONS MODULE - LIVE
val live: ZLayer[MatrixModule, Nothing, ATModule] =
ZLayer.fromService { matrixSvc =>
new Service {
def applyTf(tf: AT, vec: Vec) =
matrixSvc.mul(tf.direct, v)
/* ... */
}
}
LAYER 1: TRANSFORMATIONS
CAMERA
object Camera {
def make(
viewFrom: Pt,
viewTo: Pt,
upDirection: Vec,
visualAngleRad: Double,
hRes: Int,
vRes: Int):
ZIO[ATModule, AlgebraicError, Camera] =
worldTransformation(viewFrom, viewTo, upDirection).map {
worldTf => Camera(hRes, vRes, visualAngleRad, worlfTf)
}
CAMERA
object Camera {
def make(
viewFrom: Pt,
viewTo: Pt,
upDirection: Vec,
visualAngleRad: Double,
hRes: Int,
vRes: Int):
ZIO[ATModule, AlgebraicError, Camera] =
worldTransformation(viewFrom, viewTo, upDirection).map {
worldTf => Camera(hRes, vRes, visualAngleRad, worlfTf)
}
WORLD
sealed trait Shape {
def transformation: AT
def material: Material
}
case class Sphere(transformation: AT, material: Material) extends Shape
case class Plane(transformation: AT, material: Material) extends Shape
WORLD
▸ Sphere.canonical
sealed trait Shape {
def transformation: AT
def material: Material
}
case class Sphere(transformation: AT, material: Material) extends Shape
case class Plane(transformation: AT, material: Material) extends Shape
WORLD
▸ Sphere.canonical
▸ Plane.canonical
sealed trait Shape {
def transformation: AT
def material: Material
}
case class Sphere(transformation: AT, material: Material) extends Shape
case class Plane(transformation: AT, material: Material) extends Shape
WORLD
▸ Sphere.canonical
▸ Plane.canonical
sealed trait Shape {
def transformation: AT
def material: Material
}
case class Sphere(transformation: AT, material: Material) extends Shape
case class Plane(transformation: AT, material: Material) extends Shape
WORLD
▸ Sphere.canonical
▸ Plane.canonical
sealed trait Shape {
def transformation: AT
def material: Material
}
case class Sphere(transformation: AT, material: Material) extends Shape
case class Plane(transformation: AT, material: Material) extends Shape
WORLD
▸ Sphere.canonical
▸ Plane.canonical
sealed trait Shape {
def transformation: AT
def material: Material
}
case class Sphere(transformation: AT, material: Material) extends Shape
case class Plane(transformation: AT, material: Material) extends Shape
WORLD
▸ Sphere.canonical
▸ Plane.canonical
sealed trait Shape {
def transformation: AT
def material: Material
}
case class Sphere(transformation: AT, material: Material) extends Shape
case class Plane(transformation: AT, material: Material) extends Shape
WORLD
MAKE A WORLD
object Sphere {
def make(center: Pt, radius: Double, mat: Material): ZIO[ATModule, ATError, Sphere] = for {
scale <- ATModule.scale(radius, radius, radius)
translate <- ATModule.translate(center.x, center.y, center.z)
composed <- ATModule.compose(scale, translate)
} yield Sphere(composed, mat)
}
object Plane {
def make(...): ZIO[ATModule, ATError, Plane] = ???
}
case class World(pointLight: PointLight, objects: List[Shape])
WORLD
MAKE A WORLD
object Sphere {
def make(center: Pt, radius: Double, mat: Material): ZIO[ATModule, ATError, Sphere] = for {
scale <- ATModule.scale(radius, radius, radius)
translate <- ATModule.translate(center.x, center.y, center.z)
composed <- ATModule.compose(scale, translate)
} yield Sphere(composed, mat)
}
object Plane {
def make(...): ZIO[ATModule, ATError, Plane] = ???
}
case class World(pointLight: PointLight, objects: List[Shape])
WORLD
MAKE A WORLD
object Sphere {
def make(center: Pt, radius: Double, mat: Material): ZIO[ATModule, ATError, Sphere] = for {
scale <- ATModule.scale(radius, radius, radius)
translate <- ATModule.translate(center.x, center.y, center.z)
composed <- ATModule.compose(scale, translate)
} yield Sphere(composed, mat)
}
object Plane {
def make(...): ZIO[ATModule, ATError, Plane] = ???
}
case class World(pointLight: PointLight, objects: List[Shape])
WORLD
MAKE A WORLD
object Sphere {
def make(center: Pt, radius: Double, mat: Material): ZIO[ATModule, ATError, Sphere] = for {
scale <- ATModule.scale(radius, radius, radius)
translate <- ATModule.translate(center.x, center.y, center.z)
composed <- ATModule.compose(scale, translate)
} yield Sphere(composed, mat)
}
object Plane {
def make(...): ZIO[ATModule, ATError, Plane] = ???
}
case class World(pointLight: PointLight, objects: List[Shape])
WORLD
MAKE A WORLD
object Sphere {
def make(center: Pt, radius: Double, mat: Material): ZIO[ATModule, ATError, Sphere] = for {
scale <- ATModule.scale(radius, radius, radius)
translate <- ATModule.translate(center.x, center.y, center.z)
composed <- ATModule.compose(scale, translate)
} yield Sphere(composed, mat)
}
object Plane {
def make(...): ZIO[ATModule, ATError, Plane] = ???
}
case class World(pointLight: PointLight, objects: List[Shape])
WORLD
MAKE A WORLD
object Sphere {
def make(center: Pt, radius: Double, mat: Material): ZIO[ATModule, ATError, Sphere] = for {
scale <- ATModule.scale(radius, radius, radius)
translate <- ATModule.translate(center.x, center.y, center.z)
composed <- ATModule.compose(scale, translate)
} yield Sphere(composed, mat)
}
object Plane {
def make(...): ZIO[ATModule, ATError, Plane] = ???
}
case class World(pointLight: PointLight, objects: List[Shape])
▸ Everything requires ATModule
WORLD RENDERING - TOP DOWN
RASTERING - GENERATE A STREAM OF COLORED PIXELS
type RasteringModule = Has[Service]
object RasteringModule {
trait Service {
def raster(world: World, camera: Camera):
Stream[RayTracerError, ColoredPixel]
}
}
WORLD RENDERING - TOP DOWN
RASTERING - Live
type CameraModule = Has[Service]
object CameraModule {
trait Service {
def rayForPixel(
camera: Camera, px: Int, py: Int
): UIO[Ray]
}
}
type WorldModule = Has[Service]
object WorldModule {
trait Service {
def colorForRay(
world: World, ray: Ray
): IO[RayTracerError, Color]
}
}
WORLD RENDERING - TOP DOWN
RASTERING - Live
▸ Camera module - Ray per pixel
type CameraModule = Has[Service]
object CameraModule {
trait Service {
def rayForPixel(
camera: Camera, px: Int, py: Int
): UIO[Ray]
}
}
type WorldModule = Has[Service]
object WorldModule {
trait Service {
def colorForRay(
world: World, ray: Ray
): IO[RayTracerError, Color]
}
}
WORLD RENDERING - TOP DOWN
RASTERING - Live
▸ Camera module - Ray per pixel
type CameraModule = Has[Service]
object CameraModule {
trait Service {
def rayForPixel(
camera: Camera, px: Int, py: Int
): UIO[Ray]
}
}
type WorldModule = Has[Service]
object WorldModule {
trait Service {
def colorForRay(
world: World, ray: Ray
): IO[RayTracerError, Color]
}
}
WORLD RENDERING - TOP DOWN
RASTERING - Live
▸ Camera module - Ray per pixel
type CameraModule = Has[Service]
object CameraModule {
trait Service {
def rayForPixel(
camera: Camera, px: Int, py: Int
): UIO[Ray]
}
}
type WorldModule = Has[Service]
object WorldModule {
trait Service {
def colorForRay(
world: World, ray: Ray
): IO[RayTracerError, Color]
}
}
WORLD RENDERING - TOP DOWN
RASTERING - Live
▸ Camera module - Ray per pixel
type CameraModule = Has[Service]
object CameraModule {
trait Service {
def rayForPixel(
camera: Camera, px: Int, py: Int
): UIO[Ray]
}
}
type WorldModule = Has[Service]
object WorldModule {
trait Service {
def colorForRay(
world: World, ray: Ray
): IO[RayTracerError, Color]
}
}
WORLD RENDERING - TOP DOWN
RASTERING - Live
▸ Camera module - Ray per pixel
type CameraModule = Has[Service]
object CameraModule {
trait Service {
def rayForPixel(
camera: Camera, px: Int, py: Int
): UIO[Ray]
}
}
▸ World module - Color per ray
type WorldModule = Has[Service]
object WorldModule {
trait Service {
def colorForRay(
world: World, ray: Ray
): IO[RayTracerError, Color]
}
}
WORLD RENDERING - TOP DOWN
RASTERING - Live
▸ Camera module - Ray per pixel
type CameraModule = Has[Service]
object CameraModule {
trait Service {
def rayForPixel(
camera: Camera, px: Int, py: Int
): UIO[Ray]
}
}
▸ World module - Color per ray
type WorldModule = Has[Service]
object WorldModule {
trait Service {
def colorForRay(
world: World, ray: Ray
): IO[RayTracerError, Color]
}
}
WORLD RENDERING - TOP DOWN
RASTERING - Live
▸ Camera module - Ray per pixel
type CameraModule = Has[Service]
object CameraModule {
trait Service {
def rayForPixel(
camera: Camera, px: Int, py: Int
): UIO[Ray]
}
}
▸ World module - Color per ray
type WorldModule = Has[Service]
object WorldModule {
trait Service {
def colorForRay(
world: World, ray: Ray
): IO[RayTracerError, Color]
}
}
WORLD RENDERING - TOP DOWN
RASTERING Live - MODULE DEPENDENCY
val chunkRasteringModule: ZLayer[CameraModule with WorldModule, Nothing, RasteringModule] =
ZLayer.fromServices[cameraModule.Service, worldModule.Service, rasteringModule.Service] {
(cameraSvc, worldSvc) =>
new Service {
override def raster(world: World, camera: Camera):
Stream[Any, RayTracerError, ColoredPixel] = {
val pixels: Stream[Nothing, (Int, Int)] = ???
pixels.mapM{
case (px, py) =>
for {
ray <- cameraModule.rayForPixel(camera, px, py)
color <- worldModule.colorForRay(world, ray)
} yield data.ColoredPixel(Pixel(px, py), color)
}
}
}
}
WORLD RENDERING - TOP DOWN
RASTERING Live - MODULE DEPENDENCY
val chunkRasteringModule: ZLayer[CameraModule with WorldModule, Nothing, RasteringModule] =
ZLayer.fromServices[cameraModule.Service, worldModule.Service, rasteringModule.Service] {
(cameraSvc, worldSvc) =>
new Service {
override def raster(world: World, camera: Camera):
Stream[Any, RayTracerError, ColoredPixel] = {
val pixels: Stream[Nothing, (Int, Int)] = ???
pixels.mapM{
case (px, py) =>
for {
ray <- cameraModule.rayForPixel(camera, px, py)
color <- worldModule.colorForRay(world, ray)
} yield data.ColoredPixel(Pixel(px, py), color)
}
}
}
}
WORLD RENDERING - TOP DOWN
RASTERING Live - MODULE DEPENDENCY
val chunkRasteringModule: ZLayer[CameraModule with WorldModule, Nothing, RasteringModule] =
ZLayer.fromServices[cameraModule.Service, worldModule.Service, rasteringModule.Service] {
(cameraSvc, worldSvc) =>
new Service {
override def raster(world: World, camera: Camera):
Stream[Any, RayTracerError, ColoredPixel] = {
val pixels: Stream[Nothing, (Int, Int)] = ???
pixels.mapM{
case (px, py) =>
for {
ray <- cameraModule.rayForPixel(camera, px, py)
color <- worldModule.colorForRay(world, ray)
} yield data.ColoredPixel(Pixel(px, py), color)
}
}
}
}
LAYERS
TAKEAWAY
IMPLEMENT AND TEST EVERY LAYER ONLY IN TERMS OF THE IMMEDIATELY UNDERLYING LAYER
LIVE CameraModule
object CameraModule {
val live: ZLayer[ATModule, Nothing, CameraModule] =
ZLayer.fromService { atSvc =>
/* ... */
}
}
LIVE WorldModule
WorldTopologyModule
object WorldTopologyModule {
trait Service {
def intersections(world: World, ray: Ray):
UIO[List[Intersection]]
def isShadowed(world: World, pt: Pt):
UIO[Boolean]
}
}
LIVE WorldModule
WorldTopologyModule
object WorldTopologyModule {
trait Service {
def intersections(world: World, ray: Ray):
UIO[List[Intersection]]
def isShadowed(world: World, pt: Pt):
UIO[Boolean]
}
}
LIVE WorldModule
WorldHitCompsModule
case class HitComps(
shape: Shape, hitPt: Pt, normalV: Vec, eyeV: Vec,
rayReflectV: Vec, n1: Double = 1, n2: Double = 1
)
object WorldHitCompsModule {
trait Service {
def hitComps(
ray: Ray, hit: Intersection,
intersections: List[Intersection]
): IO[GenericError, HitComps]
}
}
LIVE WorldModule
WorldHitCompsModule
case class HitComps(
shape: Shape, hitPt: Pt, normalV: Vec, eyeV: Vec,
rayReflectV: Vec, n1: Double = 1, n2: Double = 1
)
object WorldHitCompsModule {
trait Service {
def hitComps(
ray: Ray, hit: Intersection,
intersections: List[Intersection]
): IO[GenericError, HitComps]
}
}
LIVE WorldModule
PhongReflectionModule
case class PhongComponents(
ambient: Color, diffuse: Color, reflective: Color
) {
def toColor: Color = ambient + diffuse + reflective
}
object PhongReflectionModule {
trait Service {
def lighting(
pointLight: PointLight, hitComps: HitComps,
inShadow: Boolean
): UIO[PhongComponents]
}
}
LIVE WorldModule
PhongReflectionModule
case class PhongComponents(
ambient: Color, diffuse: Color, reflective: Color
) {
def toColor: Color = ambient + diffuse + reflective
}
object PhongReflectionModule {
trait Service {
def lighting(
pointLight: PointLight, hitComps: HitComps,
inShadow: Boolean
): UIO[PhongComponents]
}
}
REFLECT THE LIGTHT SOURCE
Describe material properties
case class Material(
color: Color, // the basic color
ambient: Double, // ∈ [0, 1]
diffuse: Double, // ∈ [0, 1]
specular: Double, // ∈ [0, 1]
shininess: Double, // ∈ [10, 200]
)
LIVE PhongReflectionModule
WITH LightDiffusion AND LightReflection
object PhongReflectionModule {
trait Service { }
val live: ZLayer[ATModule
with LightDiffusionModule
with LightReflectionModule,
Nothing,
PhongReflectionModule]
}
DRAWING PROGRAM
def draw(sceneBundle: SceneBundle):
ZIO[CanvasSerializer
with RasteringModule
with ATModule,
Nothing,
Array[Byte]]
WITH HTTP4S
class DrawRoutes[R <: CanvasSerializer with RasteringModule with ATModule] {
type F[A] = RIO[R, A]
private val http4sDsl = new Http4sDsl[F] {}
import http4sDsl._
val httpRoutes: HttpRoutes[F] = HttpRoutes.of[F] {
case req @ POST -> Root / "draw" =>
req.decode[Scene] { scene =>
(for {
bundle <- Http2World.httpScene2World(scene)
bytes <- draw(bundle)
} yield bytes).foldM {
e => InternalServerError(s"something went wrong"),
Ok(bytes, "image/png")
}
}
}
}
AND IN MAIN
Provide the layers
val world: ZLayer[ATModule, Nothing, WorldModule] =
(topologyM ++ hitCompsM ++ phongM) >>> worldModule.live
val rastering: ZLayer[ATModule, Nothing, RasteringModule] =
(world ++ cameraModule.live) >>> rasteringModule.chunkRasteringModule
val full: ZLayer.NoDeps[Nothing, Rastering] = (layers.atM >>> rastering)
object Main extends zio.App {
override def run(args: List[String]): ZIO[ZEnv, Nothing, Int] =
httpProgram.provideLayer(full)
}
Swapping modules
▸ Red: reflective = 0.9
▸ Green/white: reflective = 0.6
▸ Blue: reflective = 0.9, transparency: 1
val world: ZLayer[ATModule, Nothing, WorldModule] =
(topologyM ++ hitCompsM ++ phongM) >>> worldModule.opaque
Swapping modules
▸ Red: reflective = 0.9
▸ Green/white: reflective = 0.6
▸ Blue: reflective = 0.9, transparency: 1
val world: ZLayer[ATModule, Nothing, WorldModule] =
(topologyM ++ hitCompsM ++ phongM) >>> worldModule.live
CONCLUSION - ZLayer
CONCLUSION - ZLayer
▸ Dependency graph in the code
!
CONCLUSION - ZLayer
▸ Dependency graph in the code
!
▸ Type safety, no magic
"
CONCLUSION - ZLayer
▸ Dependency graph in the code
!
▸ Type safety, no magic
"
▸ Compiler helps to satisfy requirements
CONCLUSION - ZLayer
▸ Dependency graph in the code
!
▸ Type safety, no magic
"
▸ Compiler helps to satisfy requirements
▸ Try it out, and join ZIO Discord channel
Thank you!
@pierangelocecc
https://github.com/pierangeloc/ray-tracer-zio

More Related Content

What's hot

Taking your side effects aside
Taking your side effects asideTaking your side effects aside
Taking your side effects aside
💡 Tomasz Kogut
 
The Ring programming language version 1.7 book - Part 38 of 196
The Ring programming language version 1.7 book - Part 38 of 196The Ring programming language version 1.7 book - Part 38 of 196
The Ring programming language version 1.7 book - Part 38 of 196
Mahmoud Samir Fayed
 
How to extend map? Or why we need collections redesign? - Scalar 2017
How to extend map? Or why we need collections redesign? - Scalar 2017How to extend map? Or why we need collections redesign? - Scalar 2017
How to extend map? Or why we need collections redesign? - Scalar 2017
Szymon Matejczyk
 
The Ring programming language version 1.3 book - Part 25 of 88
The Ring programming language version 1.3 book - Part 25 of 88The Ring programming language version 1.3 book - Part 25 of 88
The Ring programming language version 1.3 book - Part 25 of 88
Mahmoud Samir Fayed
 
SPL 6.1 | Advanced problems on Operators and Math.h function in C
SPL 6.1 | Advanced problems on Operators and Math.h function in CSPL 6.1 | Advanced problems on Operators and Math.h function in C
SPL 6.1 | Advanced problems on Operators and Math.h function in C
Mohammad Imam Hossain
 
ECMAScript 5: Новое в JavaScript
ECMAScript 5: Новое в JavaScriptECMAScript 5: Новое в JavaScript
Concurrent Application Development using Scala
Concurrent Application Development using ScalaConcurrent Application Development using Scala
Concurrent Application Development using Scala
Siarhiej Siemianchuk
 
How to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftHow to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftGiordano Scalzo
 
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
Wanbok Choi
 
Advance java
Advance javaAdvance java
Advance java
Vivek Kumar Sinha
 
미려한 UI/UX를 위한 여정
미려한 UI/UX를 위한 여정미려한 UI/UX를 위한 여정
미려한 UI/UX를 위한 여정
SeungChul Kang
 
The Ring programming language version 1.10 book - Part 33 of 212
The Ring programming language version 1.10 book - Part 33 of 212The Ring programming language version 1.10 book - Part 33 of 212
The Ring programming language version 1.10 book - Part 33 of 212
Mahmoud Samir Fayed
 
Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...
Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...
Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...
Philip Schwarz
 
Streams for (Co)Free!
Streams for (Co)Free!Streams for (Co)Free!
Streams for (Co)Free!
John De Goes
 
ADA FILE
ADA FILEADA FILE
ADA FILE
Gaurav Singh
 
Docopt
DocoptDocopt
Docopt
René Ribaud
 
The Uncertain Enterprise
The Uncertain EnterpriseThe Uncertain Enterprise
The Uncertain Enterprise
ClarkTony
 
Solutionsfor co2 C Programs for data structures
Solutionsfor co2 C Programs for data structuresSolutionsfor co2 C Programs for data structures
Solutionsfor co2 C Programs for data structures
Lakshmi Sarvani Videla
 

What's hot (20)

Taking your side effects aside
Taking your side effects asideTaking your side effects aside
Taking your side effects aside
 
The Ring programming language version 1.7 book - Part 38 of 196
The Ring programming language version 1.7 book - Part 38 of 196The Ring programming language version 1.7 book - Part 38 of 196
The Ring programming language version 1.7 book - Part 38 of 196
 
How to extend map? Or why we need collections redesign? - Scalar 2017
How to extend map? Or why we need collections redesign? - Scalar 2017How to extend map? Or why we need collections redesign? - Scalar 2017
How to extend map? Or why we need collections redesign? - Scalar 2017
 
ProgrammingwithGOLang
ProgrammingwithGOLangProgrammingwithGOLang
ProgrammingwithGOLang
 
The Ring programming language version 1.3 book - Part 25 of 88
The Ring programming language version 1.3 book - Part 25 of 88The Ring programming language version 1.3 book - Part 25 of 88
The Ring programming language version 1.3 book - Part 25 of 88
 
SPL 6.1 | Advanced problems on Operators and Math.h function in C
SPL 6.1 | Advanced problems on Operators and Math.h function in CSPL 6.1 | Advanced problems on Operators and Math.h function in C
SPL 6.1 | Advanced problems on Operators and Math.h function in C
 
ECMAScript 5: Новое в JavaScript
ECMAScript 5: Новое в JavaScriptECMAScript 5: Новое в JavaScript
ECMAScript 5: Новое в JavaScript
 
Concurrent Application Development using Scala
Concurrent Application Development using ScalaConcurrent Application Development using Scala
Concurrent Application Development using Scala
 
How to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftHow to Clone Flappy Bird in Swift
How to Clone Flappy Bird in Swift
 
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
 
Advance java
Advance javaAdvance java
Advance java
 
미려한 UI/UX를 위한 여정
미려한 UI/UX를 위한 여정미려한 UI/UX를 위한 여정
미려한 UI/UX를 위한 여정
 
The Ring programming language version 1.10 book - Part 33 of 212
The Ring programming language version 1.10 book - Part 33 of 212The Ring programming language version 1.10 book - Part 33 of 212
The Ring programming language version 1.10 book - Part 33 of 212
 
Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...
Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...
Side by Side - Scala and Java Adaptations of Martin Fowler’s Javascript Refac...
 
Streams for (Co)Free!
Streams for (Co)Free!Streams for (Co)Free!
Streams for (Co)Free!
 
ADA FILE
ADA FILEADA FILE
ADA FILE
 
Docopt
DocoptDocopt
Docopt
 
The Uncertain Enterprise
The Uncertain EnterpriseThe Uncertain Enterprise
The Uncertain Enterprise
 
Struct examples
Struct examplesStruct examples
Struct examples
 
Solutionsfor co2 C Programs for data structures
Solutionsfor co2 C Programs for data structuresSolutionsfor co2 C Programs for data structures
Solutionsfor co2 C Programs for data structures
 

Similar to Ray tracing with ZIO-ZLayer

Berlin meetup
Berlin meetupBerlin meetup
Berlin meetup
Wiem Zine Elabidine
 
Environmental effects - a ray tracing exercise
Environmental effects - a ray tracing exerciseEnvironmental effects - a ray tracing exercise
Environmental effects - a ray tracing exercise
Pierangelo Cecchetto
 
ZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in Scala
Wiem Zine Elabidine
 
Zio from Home
Zio from Home Zio from Home
Zio from Home
Wiem Zine Elabidine
 
The Death of Final Tagless
The Death of Final TaglessThe Death of Final Tagless
The Death of Final Tagless
John De Goes
 
ZIO Queue
ZIO QueueZIO Queue
ZIO Queue
John De Goes
 
Very basic functional design patterns
Very basic functional design patternsVery basic functional design patterns
Very basic functional design patterns
Tomasz Kowal
 
Jay Clifford [InfluxData] | Tips & Tricks for Analyzing IIoT in Real-Time | I...
Jay Clifford [InfluxData] | Tips & Tricks for Analyzing IIoT in Real-Time | I...Jay Clifford [InfluxData] | Tips & Tricks for Analyzing IIoT in Real-Time | I...
Jay Clifford [InfluxData] | Tips & Tricks for Analyzing IIoT in Real-Time | I...
InfluxData
 
Fourier project presentation
Fourier project  presentationFourier project  presentation
Fourier project presentation
志璿 楊
 
Ruby Language - A quick tour
Ruby Language - A quick tourRuby Language - A quick tour
Ruby Language - A quick touraztack
 
Generics and Inference
Generics and InferenceGenerics and Inference
Generics and Inference
Richard Fox
 
20191116 custom operators in swift
20191116 custom operators in swift20191116 custom operators in swift
20191116 custom operators in swift
Chiwon Song
 
SeaJUG March 2004 - Groovy
SeaJUG March 2004 - GroovySeaJUG March 2004 - Groovy
SeaJUG March 2004 - GroovyTed Leung
 
A Tour to MySQL Commands
A Tour to MySQL CommandsA Tour to MySQL Commands
A Tour to MySQL Commands
Hikmat Dhamee
 
Monitoring InfluxEnterprise
Monitoring InfluxEnterpriseMonitoring InfluxEnterprise
Monitoring InfluxEnterprise
InfluxData
 
Building Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeBuilding Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeMongoDB
 
Python Performance 101
Python Performance 101Python Performance 101
Python Performance 101Ankur Gupta
 
Testing in the World of Functional Programming
Testing in the World of Functional ProgrammingTesting in the World of Functional Programming
Testing in the World of Functional Programming
Luka Jacobowitz
 

Similar to Ray tracing with ZIO-ZLayer (20)

Berlin meetup
Berlin meetupBerlin meetup
Berlin meetup
 
Environmental effects - a ray tracing exercise
Environmental effects - a ray tracing exerciseEnvironmental effects - a ray tracing exercise
Environmental effects - a ray tracing exercise
 
ZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in Scala
 
Zio from Home
Zio from Home Zio from Home
Zio from Home
 
The Death of Final Tagless
The Death of Final TaglessThe Death of Final Tagless
The Death of Final Tagless
 
ZIO Queue
ZIO QueueZIO Queue
ZIO Queue
 
ppopoff
ppopoffppopoff
ppopoff
 
Very basic functional design patterns
Very basic functional design patternsVery basic functional design patterns
Very basic functional design patterns
 
Jay Clifford [InfluxData] | Tips & Tricks for Analyzing IIoT in Real-Time | I...
Jay Clifford [InfluxData] | Tips & Tricks for Analyzing IIoT in Real-Time | I...Jay Clifford [InfluxData] | Tips & Tricks for Analyzing IIoT in Real-Time | I...
Jay Clifford [InfluxData] | Tips & Tricks for Analyzing IIoT in Real-Time | I...
 
Fourier project presentation
Fourier project  presentationFourier project  presentation
Fourier project presentation
 
Ruby Language - A quick tour
Ruby Language - A quick tourRuby Language - A quick tour
Ruby Language - A quick tour
 
Generics and Inference
Generics and InferenceGenerics and Inference
Generics and Inference
 
20191116 custom operators in swift
20191116 custom operators in swift20191116 custom operators in swift
20191116 custom operators in swift
 
SeaJUG March 2004 - Groovy
SeaJUG March 2004 - GroovySeaJUG March 2004 - Groovy
SeaJUG March 2004 - Groovy
 
Django (Web Konferencia 2009)
Django (Web Konferencia 2009)Django (Web Konferencia 2009)
Django (Web Konferencia 2009)
 
A Tour to MySQL Commands
A Tour to MySQL CommandsA Tour to MySQL Commands
A Tour to MySQL Commands
 
Monitoring InfluxEnterprise
Monitoring InfluxEnterpriseMonitoring InfluxEnterprise
Monitoring InfluxEnterprise
 
Building Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeBuilding Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at Stripe
 
Python Performance 101
Python Performance 101Python Performance 101
Python Performance 101
 
Testing in the World of Functional Programming
Testing in the World of Functional ProgrammingTesting in the World of Functional Programming
Testing in the World of Functional Programming
 

Recently uploaded

Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
rickgrimesss22
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
Globus
 
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
XfilesPro
 
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Mind IT Systems
 
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoamOpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
takuyayamamoto1800
 
May Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdfMay Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdf
Adele Miller
 
Enterprise Resource Planning System in Telangana
Enterprise Resource Planning System in TelanganaEnterprise Resource Planning System in Telangana
Enterprise Resource Planning System in Telangana
NYGGS Automation Suite
 
top nidhi software solution freedownload
top nidhi software solution freedownloadtop nidhi software solution freedownload
top nidhi software solution freedownload
vrstrong314
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
Globus
 
Graphic Design Crash Course for beginners
Graphic Design Crash Course for beginnersGraphic Design Crash Course for beginners
Graphic Design Crash Course for beginners
e20449
 
Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604
Fermin Galan
 
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Globus
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Globus
 
A Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdfA Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdf
kalichargn70th171
 
Cyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdfCyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdf
Cyanic lab
 
GlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote sessionGlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote session
Globus
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdf
Ortus Solutions, Corp
 
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar
 
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
Tier1 app
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns
 

Recently uploaded (20)

Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
 
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
 
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
 
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoamOpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
 
May Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdfMay Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdf
 
Enterprise Resource Planning System in Telangana
Enterprise Resource Planning System in TelanganaEnterprise Resource Planning System in Telangana
Enterprise Resource Planning System in Telangana
 
top nidhi software solution freedownload
top nidhi software solution freedownloadtop nidhi software solution freedownload
top nidhi software solution freedownload
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
 
Graphic Design Crash Course for beginners
Graphic Design Crash Course for beginnersGraphic Design Crash Course for beginners
Graphic Design Crash Course for beginners
 
Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604
 
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
 
A Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdfA Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdf
 
Cyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdfCyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdf
 
GlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote sessionGlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote session
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdf
 
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBroker
 
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
 

Ray tracing with ZIO-ZLayer

  • 1. ZLayer A RAY TRACING EXERCISE PIERANGELO CECCHETTO Functional Rotterdam 04 Mar 2020
  • 2. ZIO-101 ZIO[-R, +E, +A] ➡ R => IO[Either[E, A]] ➡ R => Either[E, A]
  • 3. ZIO-101: PROGRAMS val prg: ZIO[Console with Random, Nothing, Long] = for { n <- random.nextLong // ZIO[Random, Nothing, Long] _ <- console.putStrLn(s"Extracted $n ") // ZIO[Console, Nothing, Unit] } yield n val allNrs: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAll(List.fill(100)(prg)) val allNrsPar: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllPar(List.fill(100)(prg)) val allNrsParN: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllParN(10)(List.fill(100)(prg))
  • 4. ZIO-101: PROGRAMS ▸ ZIO programs are values val prg: ZIO[Console with Random, Nothing, Long] = for { n <- random.nextLong // ZIO[Random, Nothing, Long] _ <- console.putStrLn(s"Extracted $n ") // ZIO[Console, Nothing, Unit] } yield n val allNrs: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAll(List.fill(100)(prg)) val allNrsPar: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllPar(List.fill(100)(prg)) val allNrsParN: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllParN(10)(List.fill(100)(prg))
  • 5. ZIO-101: PROGRAMS ▸ ZIO programs are values ▸ Concurrency based on fibers (green threads) val prg: ZIO[Console with Random, Nothing, Long] = for { n <- random.nextLong // ZIO[Random, Nothing, Long] _ <- console.putStrLn(s"Extracted $n ") // ZIO[Console, Nothing, Unit] } yield n val allNrs: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAll(List.fill(100)(prg)) val allNrsPar: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllPar(List.fill(100)(prg)) val allNrsParN: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllParN(10)(List.fill(100)(prg))
  • 6. ZIO-101: PROGRAMS ▸ ZIO programs are values ▸ Concurrency based on fibers (green threads) val prg: ZIO[Console with Random, Nothing, Long] = for { n <- random.nextLong // ZIO[Random, Nothing, Long] _ <- console.putStrLn(s"Extracted $n ") // ZIO[Console, Nothing, Unit] } yield n val allNrs: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAll(List.fill(100)(prg)) val allNrsPar: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllPar(List.fill(100)(prg)) val allNrsParN: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllParN(10)(List.fill(100)(prg))
  • 7. ZIO-101: PROGRAMS ▸ ZIO programs are values ▸ Concurrency based on fibers (green threads) val prg: ZIO[Console with Random, Nothing, Long] = for { n <- random.nextLong // ZIO[Random, Nothing, Long] _ <- console.putStrLn(s"Extracted $n ") // ZIO[Console, Nothing, Unit] } yield n val allNrs: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAll(List.fill(100)(prg)) val allNrsPar: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllPar(List.fill(100)(prg)) val allNrsParN: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllParN(10)(List.fill(100)(prg))
  • 8. ZIO-101: PROGRAMS ▸ ZIO programs are values ▸ Concurrency based on fibers (green threads) val prg: ZIO[Console with Random, Nothing, Long] = for { n <- random.nextLong // ZIO[Random, Nothing, Long] _ <- console.putStrLn(s"Extracted $n ") // ZIO[Console, Nothing, Unit] } yield n val allNrs: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAll(List.fill(100)(prg)) val allNrsPar: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllPar(List.fill(100)(prg)) val allNrsParN: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllParN(10)(List.fill(100)(prg))
  • 9. ZIO-101: PROGRAMS ▸ ZIO programs are values ▸ Concurrency based on fibers (green threads) val prg: ZIO[Console with Random, Nothing, Long] = for { n <- random.nextLong // ZIO[Random, Nothing, Long] _ <- console.putStrLn(s"Extracted $n ") // ZIO[Console, Nothing, Unit] } yield n val allNrs: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAll(List.fill(100)(prg)) val allNrsPar: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllPar(List.fill(100)(prg)) val allNrsParN: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllParN(10)(List.fill(100)(prg))
  • 10. ZIO-101: PROGRAMS ▸ ZIO programs are values ▸ Concurrency based on fibers (green threads) val prg: ZIO[Console with Random, Nothing, Long] = for { n <- random.nextLong // ZIO[Random, Nothing, Long] _ <- console.putStrLn(s"Extracted $n ") // ZIO[Console, Nothing, Unit] } yield n val allNrs: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAll(List.fill(100)(prg)) val allNrsPar: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllPar(List.fill(100)(prg)) val allNrsParN: ZIO[Console with Random, Nothing, List[Long]] = ZIO.collectAllParN(10)(List.fill(100)(prg))
  • 11. ZIO-101: R MEANS REQUIREMENT val prg: ZIO[Console with Random, Nothing, Long] = ??? val autonomous: ZIO[Any, Nothing, Long] = ??? val getUserFromDb: ZIO[DBConnection, Nothing, User] = ???
  • 12. ZIO-101: R MEANS REQUIREMENT val prg: ZIO[Console with Random, Nothing, Long] = ??? val autonomous: ZIO[Any, Nothing, Long] = ??? val getUserFromDb: ZIO[DBConnection, Nothing, User] = ???
  • 13. ZIO-101: R MEANS REQUIREMENT val prg: ZIO[Console with Random, Nothing, Long] = ??? val autonomous: ZIO[Any, Nothing, Long] = ??? val getUserFromDb: ZIO[DBConnection, Nothing, User] = ???
  • 14. ZIO-101: R MEANS REQUIREMENT val prg: ZIO[Console with Random, Nothing, Long] = ??? val autonomous: ZIO[Any, Nothing, Long] = ??? val getUserFromDb: ZIO[DBConnection, Nothing, User] = ???
  • 15. ZIO-101: REQUIREMENTS ELIMINATION val getUserFromDb: ZIO[DBConnection, Nothing, User] = ??? val provided: ZIO[Any, Nothing, User] = getUserFromDb.provide(DBConnection(...)) val user: User = Runtime.default.unsafeRun(provided)
  • 16. ZIO-101: REQUIREMENTS ELIMINATION val getUserFromDb: ZIO[DBConnection, Nothing, User] = ??? val provided: ZIO[Any, Nothing, User] = getUserFromDb.provide(DBConnection(...)) val user: User = Runtime.default.unsafeRun(provided)
  • 17. ZIO-101: REQUIREMENTS ELIMINATION val getUserFromDb: ZIO[DBConnection, Nothing, User] = ??? val provided: ZIO[Any, Nothing, User] = getUserFromDb.provide(DBConnection(...)) val user: User = Runtime.default.unsafeRun(provided)
  • 18. ZIO-101: REQUIREMENTS ELIMINATION val getUserFromDb: ZIO[DBConnection, Nothing, User] = ??? val provided: ZIO[Any, Nothing, User] = getUserFromDb.provide(DBConnection(...)) val user: User = Runtime.default.unsafeRun(provided)
  • 19. ZIO-101: MODULES Example: a module to collect metrics1 type Metrics = Has[Metrics.Service] object Metrics { trait Service { def inc(label: String): IO[Nothing, Unit] } //accessor method def inc(label: String): ZIO[Metrics, Nothing, Unit] = ZIO.accessM(_.get.inc(label)) } } 1 ZIO 1.0.0-RC18
  • 20. ZIO-101: MODULES Example: a module to collect metrics1 type Metrics = Has[Metrics.Service] object Metrics { trait Service { def inc(label: String): IO[Nothing, Unit] } //accessor method def inc(label: String): ZIO[Metrics, Nothing, Unit] = ZIO.accessM(_.get.inc(label)) } } 1 ZIO 1.0.0-RC18
  • 21. ZIO-101: MODULES Example: a module to collect metrics1 type Metrics = Has[Metrics.Service] object Metrics { trait Service { def inc(label: String): IO[Nothing, Unit] } //accessor method def inc(label: String): ZIO[Metrics, Nothing, Unit] = ZIO.accessM(_.get.inc(label)) } } 1 ZIO 1.0.0-RC18
  • 22. ZIO-101: MODULES Example: a module for logging type Log = Has[Log.Service] object Log { trait Service { def info(s: String): IO[Nothing, Unit] def error(s: String): IO[Nothing, Unit] } //accessor methods... }
  • 23. ZIO-101: MODULES Write a program using existing modules val prg: ZIO[Metrics with Log, Nothing, Unit] = for { _ <- Log.info("Hello") _ <- Metrics.inc("salutation") _ <- Log.info("Rotterdam") _ <- Metrics.inc("subject") } yield ()
  • 24. ZIO-101: THE Has DATA TYPE Has[A] is a dependency on a service of type A val hasLog: Has[Log.Service] // type Log = Has[Log.Service] val hasMetrics: Has[Metrics.Service] // type Metrics = Has[Metrics.Service] val mix: Log with Metrics = hasLog ++ hasMetrics //access each service mix.get[Log.Service].info("Starting the application")
  • 25. ZIO-101: THE Has DATA TYPE Has[A] is a dependency on a service of type A val hasLog: Has[Log.Service] // type Log = Has[Log.Service] val hasMetrics: Has[Metrics.Service] // type Metrics = Has[Metrics.Service] val mix: Log with Metrics = hasLog ++ hasMetrics //access each service mix.get[Log.Service].info("Starting the application")
  • 26. ZIO-101: THE Has DATA TYPE val mix: Log with Metrics = hasLog ++ hasMetrics mix.get[Log.Service].info("Starting the application")
  • 27. ZIO-101: THE Has DATA TYPE val mix: Log with Metrics = hasLog ++ hasMetrics mix.get[Log.Service].info("Starting the application") ▸ Is more powerful than trait mixins
  • 28. ZIO-101: THE Has DATA TYPE val mix: Log with Metrics = hasLog ++ hasMetrics mix.get[Log.Service].info("Starting the application") ▸ Is more powerful than trait mixins ▸ Is backed by a heterogeneus map ServiceType -> Service
  • 29. ZIO-101: THE Has DATA TYPE val mix: Log with Metrics = hasLog ++ hasMetrics mix.get[Log.Service].info("Starting the application") ▸ Is more powerful than trait mixins ▸ Is backed by a heterogeneus map ServiceType -> Service ▸ Can replace/update services
  • 31. ZIO-101: ZLayer ZLayer[-RIn, +E, +ROut <: Has[_]] ▸ A recipe to build an ROut
  • 32. ZIO-101: ZLayer ZLayer[-RIn, +E, +ROut <: Has[_]] ▸ A recipe to build an ROut ▸ Backed by ZManaged: safe acquire/release
  • 33. ZIO-101: ZLayer ZLayer[-RIn, +E, +ROut <: Has[_]] ▸ A recipe to build an ROut ▸ Backed by ZManaged: safe acquire/release ▸ type NoDeps[+E, +B <: Has[_]] = ZLayer[Any, E, B]
  • 34. ZIO-101: ZLayer Construct from value val layer: ZLayer.NoDeps[Nothing, UserRepo] = ZLayer.succeed(new UserRepo.Service)
  • 35. ZIO-101: ZLayer Construct from function val layer: ZLayer[Connection, Nothing, UserRepo] = ZLayer.fromFunction { c: Connection => new UserRepo.Service }
  • 36. ZIO-101: ZLayer Construct from effect import java.sql.Connection val e: ZIO[Connection, Error, UserRepo.Service] val layer: ZLayer[Connection, Error, UserRepo] = ZLayer.fromEffect(e)
  • 37. ZIO-101: ZLayer Construct from resources import java.sql.Connection val connectionLayer: ZLayer.NoDeps[Nothing, Has[Connection]] = ZLayer.fromAcquireRelease(makeConnection) { c => UIO(c.close()) }
  • 38. ZIO-101: ZLayer Construct from other services val usersLayer: ZLayer[UserRepo with UserValidation, Nothing, BusinessLogic] = ZLayer.fromServices[UserRepo.Service, UserValidation.Service] { (repoSvc, validSvc) => new BusinessLogic.Service { // use repoSvc and validSvc } }
  • 39. ZIO-101: ZLayer Compose horizontally (all inputs for all outputs) val l1: ZLayer[Connection, Nothing, UserRepo] val l2: ZLayer[Config, Nothing, AuthPolicy] val hor: ZLayer[Connection with Config, Nothing, UserRepo with AuthPolicy] = l1 ++ l2
  • 40. ZIO-101: ZLayer Compose vertically (output of first for input of second) val l1: ZLayer[Config, Nothing, Connection] val l2: ZLayer[Connection, Nothing, UserRepo] val ver: ZLayer[Config, Nothing, UserRepo] = l1 >>> l2
  • 41. ZIO-101: ZLayer Create module instances type UserRepo = Has[UserRepo.Service] object UserRepo { trait Service { def getUser(userId: UserId): IO[DBError, Option[User]] def createUser(user: User): IO[DBError, Unit] } val inMemory: ZLayer.NoDeps[Nothing, UserRepo] = ZLayer.succeed( new Service { /* impl */ } ) val db: ZLayer[Connection, Nothing, UserRepo] = ZLayer.fromService { conn: Connection => new Service { /* impl uses conn */ } } }
  • 42. ZIO-101: ZLayer Create module instances type UserRepo = Has[UserRepo.Service] object UserRepo { trait Service { def getUser(userId: UserId): IO[DBError, Option[User]] def createUser(user: User): IO[DBError, Unit] } val inMemory: ZLayer.NoDeps[Nothing, UserRepo] = ZLayer.succeed( new Service { /* impl */ } ) val db: ZLayer[Connection, Nothing, UserRepo] = ZLayer.fromService { conn: Connection => new Service { /* impl uses conn */ } } }
  • 43. ZIO-101: ZLayer Create module instances type UserRepo = Has[UserRepo.Service] object UserRepo { trait Service { def getUser(userId: UserId): IO[DBError, Option[User]] def createUser(user: User): IO[DBError, Unit] } val inMemory: ZLayer.NoDeps[Nothing, UserRepo] = ZLayer.succeed( new Service { /* impl */ } ) val db: ZLayer[Connection, Nothing, UserRepo] = ZLayer.fromService { conn: Connection => new Service { /* impl uses conn */ } } }
  • 44. ZIO-101: ZLayer Provide layers to programs import zio.console.Console val checkUser: ZIO[UserRepo with AuthPolicy with Console, Nothing, Boolean] val liveLayer = UserRepo.inMemory ++ AuthPolicy.basicPolicy ++ Console.live val full: ZIO[Any, Nothing, Boolean] = checkUser.provideLayer( liveLayer ) val partial: ZIO[Console, Nothing, Boolean] = checkUser.provideSomeLayer( UserRepo.inMemory ++ AuthPolicy.basicPolicy ) val updated: ZIO[Any, Nothing, Boolean] = checkUser.provideLayer( liveLayer ++ UserRepo.postgres )
  • 45. ZIO-101: ZLayer Provide layers to programs import zio.console.Console val checkUser: ZIO[UserRepo with AuthPolicy with Console, Nothing, Boolean] val liveLayer = UserRepo.inMemory ++ AuthPolicy.basicPolicy ++ Console.live val full: ZIO[Any, Nothing, Boolean] = checkUser.provideLayer( liveLayer ) val partial: ZIO[Console, Nothing, Boolean] = checkUser.provideSomeLayer( UserRepo.inMemory ++ AuthPolicy.basicPolicy ) val updated: ZIO[Any, Nothing, Boolean] = checkUser.provideLayer( liveLayer ++ UserRepo.postgres )
  • 46. ZIO-101: ZLayer Provide layers to programs import zio.console.Console val checkUser: ZIO[UserRepo with AuthPolicy with Console, Nothing, Boolean] val liveLayer = UserRepo.inMemory ++ AuthPolicy.basicPolicy ++ Console.live val full: ZIO[Any, Nothing, Boolean] = checkUser.provideLayer( liveLayer ) val partial: ZIO[Console, Nothing, Boolean] = checkUser.provideSomeLayer( UserRepo.inMemory ++ AuthPolicy.basicPolicy ) val updated: ZIO[Any, Nothing, Boolean] = checkUser.provideLayer( liveLayer ++ UserRepo.postgres )
  • 47. ZIO-101: ZLayer Provide layers to programs import zio.console.Console val checkUser: ZIO[UserRepo with AuthPolicy with Console, Nothing, Boolean] val liveLayer = UserRepo.inMemory ++ AuthPolicy.basicPolicy ++ Console.live val full: ZIO[Any, Nothing, Boolean] = checkUser.provideLayer( liveLayer ) val partial: ZIO[Console, Nothing, Boolean] = checkUser.provideSomeLayer( UserRepo.inMemory ++ AuthPolicy.basicPolicy ) val updated: ZIO[Any, Nothing, Boolean] = checkUser.provideLayer( liveLayer ++ UserRepo.postgres )
  • 49. RAY TRACING ▸ World (spheres), light source, camera
  • 50. RAY TRACING ▸ World (spheres), light source, camera ▸ Incident rays
  • 51. RAY TRACING ▸ World (spheres), light source, camera ▸ Incident rays ▸ Reflected rays
  • 52. RAY TRACING ▸ World (spheres), light source, camera ▸ Incident rays ▸ Reflected rays ▸ Discarded rays ▸ Canvas
  • 53. RAY TRACING ▸ World (spheres), light source, camera ▸ Incident rays ▸ Reflected rays ▸ Discarded rays ▸ Canvas ▸ Colored pixels
  • 54. RAY TRACING ▸ World (spheres), light source, camera ▸ Incident rays ▸ Reflected rays ▸ Discarded rays ▸ Canvas ▸ Colored pixels
  • 56. RAY TRACING Options: 1. Compute all the rays (and discard most of them)
  • 57. RAY TRACING Options: 1. Compute all the rays (and discard most of them) 2. Compute only the rays outgoing from the camera through the canvas, and determine how they behave on the surfaces
  • 58. RAY case class Ray(origin: Pt, direction: Vec) { def positionAt(t: Double): Pt = origin + (direction * t) }
  • 59. TRANSFORMATIONS MODULE trait AT type ATModule = Has[ATModule.Service] object ATModule { /* Service */ trait Service { def applyTf(tf: AT, vec: Vec): ZIO[ATError, Vec] def applyTf(tf: AT, pt: Pt): ZIO[ATError, Pt] def compose(first: AT, second: AT): ZIO[ATError, AT] } def applyTf(tf: AT, vec: Vec): ZIO[ATModule, ATError, Vec] = ZIO.accessM(_.aTModule.applyTf(tf, vec)) def applyTf(tf: AT, pt: Pt): ZIO[ATModule, ATError, Pt] = ZIO.accessM(_.aTModule.applyTf(tf, pt)) def compose(first: AT, second: AT): ZIO[ATModule, ATError, AT] = ZIO.accessM(_.aTModule.compose(first, second)) }
  • 60. TRANSFORMATIONS MODULE val rotatedPt = for { rotateX <- ATModule.rotateX(math.Pi / 2) _ <- Log.info("rotated of π/2") res <- ATModule.applyTf(rotateX, Pt(1, 1, 1)) } yield res
  • 61. TRANSFORMATIONS MODULE val rotatedPt: ZIO[ATModule with Log, ATError, Pt] = for { rotateX <- ATModule.rotateX(math.Pi / 2) _ <- Log.info("rotated of π/2") res <- ATModule.applyTf(rotateX, Pt(1, 1, 1)) } yield res
  • 62. TRANSFORMATIONS MODULE - LIVE val rotated: ZIO[ATModule, ATError, Vec] = for { rotateX <- ATModule.rotateX(math.Pi/2) res <- ATModule.applyTf(rotateX, Pt(1, 1, 1)) } yield res
  • 63. TRANSFORMATIONS MODULE - LIVE val rotated: ZIO[ATModule, ATError, Vec] = for { rotateX <- ATModule.rotateX(math.Pi/2) res <- ATModule.applyTf(rotateX, Pt(1, 1, 1)) } yield res ▸ Vec(x, y, z)
  • 64. TRANSFORMATIONS MODULE - LIVE val rotated: ZIO[ATModule, ATError, Vec] = for { rotateX <- ATModule.rotateX(math.Pi/2) res <- ATModule.applyTf(rotateX, Pt(1, 1, 1)) } yield res ▸ Vec(x, y, z) ▸ Pt(x, y, z)⠀
  • 65. TRANSFORMATIONS MODULE - LIVE val rotated: ZIO[ATModule, ATError, Vec] = for { rotateX <- ATModule.rotateX(math.Pi/2) res <- ATModule.applyTf(rotateX, Pt(1, 1, 1)) } yield res ▸ Vec(x, y, z) ▸ Pt(x, y, z)⠀ ▸ ⠀
  • 66. TRANSFORMATIONS MODULE - LIVE val live: ZLayer[MatrixModule, Nothing, ATModule] = ZLayer.fromService { matrixSvc => new Service { def applyTf(tf: AT, vec: Vec) = matrixSvc.mul(tf.direct, v) /* ... */ } }
  • 68. CAMERA object Camera { def make( viewFrom: Pt, viewTo: Pt, upDirection: Vec, visualAngleRad: Double, hRes: Int, vRes: Int): ZIO[ATModule, AlgebraicError, Camera] = worldTransformation(viewFrom, viewTo, upDirection).map { worldTf => Camera(hRes, vRes, visualAngleRad, worlfTf) }
  • 69. CAMERA object Camera { def make( viewFrom: Pt, viewTo: Pt, upDirection: Vec, visualAngleRad: Double, hRes: Int, vRes: Int): ZIO[ATModule, AlgebraicError, Camera] = worldTransformation(viewFrom, viewTo, upDirection).map { worldTf => Camera(hRes, vRes, visualAngleRad, worlfTf) }
  • 70. WORLD sealed trait Shape { def transformation: AT def material: Material } case class Sphere(transformation: AT, material: Material) extends Shape case class Plane(transformation: AT, material: Material) extends Shape
  • 71. WORLD ▸ Sphere.canonical sealed trait Shape { def transformation: AT def material: Material } case class Sphere(transformation: AT, material: Material) extends Shape case class Plane(transformation: AT, material: Material) extends Shape
  • 72. WORLD ▸ Sphere.canonical ▸ Plane.canonical sealed trait Shape { def transformation: AT def material: Material } case class Sphere(transformation: AT, material: Material) extends Shape case class Plane(transformation: AT, material: Material) extends Shape
  • 73. WORLD ▸ Sphere.canonical ▸ Plane.canonical sealed trait Shape { def transformation: AT def material: Material } case class Sphere(transformation: AT, material: Material) extends Shape case class Plane(transformation: AT, material: Material) extends Shape
  • 74. WORLD ▸ Sphere.canonical ▸ Plane.canonical sealed trait Shape { def transformation: AT def material: Material } case class Sphere(transformation: AT, material: Material) extends Shape case class Plane(transformation: AT, material: Material) extends Shape
  • 75. WORLD ▸ Sphere.canonical ▸ Plane.canonical sealed trait Shape { def transformation: AT def material: Material } case class Sphere(transformation: AT, material: Material) extends Shape case class Plane(transformation: AT, material: Material) extends Shape
  • 76. WORLD ▸ Sphere.canonical ▸ Plane.canonical sealed trait Shape { def transformation: AT def material: Material } case class Sphere(transformation: AT, material: Material) extends Shape case class Plane(transformation: AT, material: Material) extends Shape
  • 77. WORLD MAKE A WORLD object Sphere { def make(center: Pt, radius: Double, mat: Material): ZIO[ATModule, ATError, Sphere] = for { scale <- ATModule.scale(radius, radius, radius) translate <- ATModule.translate(center.x, center.y, center.z) composed <- ATModule.compose(scale, translate) } yield Sphere(composed, mat) } object Plane { def make(...): ZIO[ATModule, ATError, Plane] = ??? } case class World(pointLight: PointLight, objects: List[Shape])
  • 78. WORLD MAKE A WORLD object Sphere { def make(center: Pt, radius: Double, mat: Material): ZIO[ATModule, ATError, Sphere] = for { scale <- ATModule.scale(radius, radius, radius) translate <- ATModule.translate(center.x, center.y, center.z) composed <- ATModule.compose(scale, translate) } yield Sphere(composed, mat) } object Plane { def make(...): ZIO[ATModule, ATError, Plane] = ??? } case class World(pointLight: PointLight, objects: List[Shape])
  • 79. WORLD MAKE A WORLD object Sphere { def make(center: Pt, radius: Double, mat: Material): ZIO[ATModule, ATError, Sphere] = for { scale <- ATModule.scale(radius, radius, radius) translate <- ATModule.translate(center.x, center.y, center.z) composed <- ATModule.compose(scale, translate) } yield Sphere(composed, mat) } object Plane { def make(...): ZIO[ATModule, ATError, Plane] = ??? } case class World(pointLight: PointLight, objects: List[Shape])
  • 80. WORLD MAKE A WORLD object Sphere { def make(center: Pt, radius: Double, mat: Material): ZIO[ATModule, ATError, Sphere] = for { scale <- ATModule.scale(radius, radius, radius) translate <- ATModule.translate(center.x, center.y, center.z) composed <- ATModule.compose(scale, translate) } yield Sphere(composed, mat) } object Plane { def make(...): ZIO[ATModule, ATError, Plane] = ??? } case class World(pointLight: PointLight, objects: List[Shape])
  • 81. WORLD MAKE A WORLD object Sphere { def make(center: Pt, radius: Double, mat: Material): ZIO[ATModule, ATError, Sphere] = for { scale <- ATModule.scale(radius, radius, radius) translate <- ATModule.translate(center.x, center.y, center.z) composed <- ATModule.compose(scale, translate) } yield Sphere(composed, mat) } object Plane { def make(...): ZIO[ATModule, ATError, Plane] = ??? } case class World(pointLight: PointLight, objects: List[Shape])
  • 82. WORLD MAKE A WORLD object Sphere { def make(center: Pt, radius: Double, mat: Material): ZIO[ATModule, ATError, Sphere] = for { scale <- ATModule.scale(radius, radius, radius) translate <- ATModule.translate(center.x, center.y, center.z) composed <- ATModule.compose(scale, translate) } yield Sphere(composed, mat) } object Plane { def make(...): ZIO[ATModule, ATError, Plane] = ??? } case class World(pointLight: PointLight, objects: List[Shape]) ▸ Everything requires ATModule
  • 83. WORLD RENDERING - TOP DOWN RASTERING - GENERATE A STREAM OF COLORED PIXELS type RasteringModule = Has[Service] object RasteringModule { trait Service { def raster(world: World, camera: Camera): Stream[RayTracerError, ColoredPixel] } }
  • 84. WORLD RENDERING - TOP DOWN RASTERING - Live type CameraModule = Has[Service] object CameraModule { trait Service { def rayForPixel( camera: Camera, px: Int, py: Int ): UIO[Ray] } } type WorldModule = Has[Service] object WorldModule { trait Service { def colorForRay( world: World, ray: Ray ): IO[RayTracerError, Color] } }
  • 85. WORLD RENDERING - TOP DOWN RASTERING - Live ▸ Camera module - Ray per pixel type CameraModule = Has[Service] object CameraModule { trait Service { def rayForPixel( camera: Camera, px: Int, py: Int ): UIO[Ray] } } type WorldModule = Has[Service] object WorldModule { trait Service { def colorForRay( world: World, ray: Ray ): IO[RayTracerError, Color] } }
  • 86. WORLD RENDERING - TOP DOWN RASTERING - Live ▸ Camera module - Ray per pixel type CameraModule = Has[Service] object CameraModule { trait Service { def rayForPixel( camera: Camera, px: Int, py: Int ): UIO[Ray] } } type WorldModule = Has[Service] object WorldModule { trait Service { def colorForRay( world: World, ray: Ray ): IO[RayTracerError, Color] } }
  • 87. WORLD RENDERING - TOP DOWN RASTERING - Live ▸ Camera module - Ray per pixel type CameraModule = Has[Service] object CameraModule { trait Service { def rayForPixel( camera: Camera, px: Int, py: Int ): UIO[Ray] } } type WorldModule = Has[Service] object WorldModule { trait Service { def colorForRay( world: World, ray: Ray ): IO[RayTracerError, Color] } }
  • 88. WORLD RENDERING - TOP DOWN RASTERING - Live ▸ Camera module - Ray per pixel type CameraModule = Has[Service] object CameraModule { trait Service { def rayForPixel( camera: Camera, px: Int, py: Int ): UIO[Ray] } } type WorldModule = Has[Service] object WorldModule { trait Service { def colorForRay( world: World, ray: Ray ): IO[RayTracerError, Color] } }
  • 89. WORLD RENDERING - TOP DOWN RASTERING - Live ▸ Camera module - Ray per pixel type CameraModule = Has[Service] object CameraModule { trait Service { def rayForPixel( camera: Camera, px: Int, py: Int ): UIO[Ray] } } ▸ World module - Color per ray type WorldModule = Has[Service] object WorldModule { trait Service { def colorForRay( world: World, ray: Ray ): IO[RayTracerError, Color] } }
  • 90. WORLD RENDERING - TOP DOWN RASTERING - Live ▸ Camera module - Ray per pixel type CameraModule = Has[Service] object CameraModule { trait Service { def rayForPixel( camera: Camera, px: Int, py: Int ): UIO[Ray] } } ▸ World module - Color per ray type WorldModule = Has[Service] object WorldModule { trait Service { def colorForRay( world: World, ray: Ray ): IO[RayTracerError, Color] } }
  • 91. WORLD RENDERING - TOP DOWN RASTERING - Live ▸ Camera module - Ray per pixel type CameraModule = Has[Service] object CameraModule { trait Service { def rayForPixel( camera: Camera, px: Int, py: Int ): UIO[Ray] } } ▸ World module - Color per ray type WorldModule = Has[Service] object WorldModule { trait Service { def colorForRay( world: World, ray: Ray ): IO[RayTracerError, Color] } }
  • 92. WORLD RENDERING - TOP DOWN RASTERING Live - MODULE DEPENDENCY val chunkRasteringModule: ZLayer[CameraModule with WorldModule, Nothing, RasteringModule] = ZLayer.fromServices[cameraModule.Service, worldModule.Service, rasteringModule.Service] { (cameraSvc, worldSvc) => new Service { override def raster(world: World, camera: Camera): Stream[Any, RayTracerError, ColoredPixel] = { val pixels: Stream[Nothing, (Int, Int)] = ??? pixels.mapM{ case (px, py) => for { ray <- cameraModule.rayForPixel(camera, px, py) color <- worldModule.colorForRay(world, ray) } yield data.ColoredPixel(Pixel(px, py), color) } } } }
  • 93. WORLD RENDERING - TOP DOWN RASTERING Live - MODULE DEPENDENCY val chunkRasteringModule: ZLayer[CameraModule with WorldModule, Nothing, RasteringModule] = ZLayer.fromServices[cameraModule.Service, worldModule.Service, rasteringModule.Service] { (cameraSvc, worldSvc) => new Service { override def raster(world: World, camera: Camera): Stream[Any, RayTracerError, ColoredPixel] = { val pixels: Stream[Nothing, (Int, Int)] = ??? pixels.mapM{ case (px, py) => for { ray <- cameraModule.rayForPixel(camera, px, py) color <- worldModule.colorForRay(world, ray) } yield data.ColoredPixel(Pixel(px, py), color) } } } }
  • 94. WORLD RENDERING - TOP DOWN RASTERING Live - MODULE DEPENDENCY val chunkRasteringModule: ZLayer[CameraModule with WorldModule, Nothing, RasteringModule] = ZLayer.fromServices[cameraModule.Service, worldModule.Service, rasteringModule.Service] { (cameraSvc, worldSvc) => new Service { override def raster(world: World, camera: Camera): Stream[Any, RayTracerError, ColoredPixel] = { val pixels: Stream[Nothing, (Int, Int)] = ??? pixels.mapM{ case (px, py) => for { ray <- cameraModule.rayForPixel(camera, px, py) color <- worldModule.colorForRay(world, ray) } yield data.ColoredPixel(Pixel(px, py), color) } } } }
  • 95. LAYERS TAKEAWAY IMPLEMENT AND TEST EVERY LAYER ONLY IN TERMS OF THE IMMEDIATELY UNDERLYING LAYER
  • 96.
  • 97. LIVE CameraModule object CameraModule { val live: ZLayer[ATModule, Nothing, CameraModule] = ZLayer.fromService { atSvc => /* ... */ } }
  • 98. LIVE WorldModule WorldTopologyModule object WorldTopologyModule { trait Service { def intersections(world: World, ray: Ray): UIO[List[Intersection]] def isShadowed(world: World, pt: Pt): UIO[Boolean] } }
  • 99. LIVE WorldModule WorldTopologyModule object WorldTopologyModule { trait Service { def intersections(world: World, ray: Ray): UIO[List[Intersection]] def isShadowed(world: World, pt: Pt): UIO[Boolean] } }
  • 100. LIVE WorldModule WorldHitCompsModule case class HitComps( shape: Shape, hitPt: Pt, normalV: Vec, eyeV: Vec, rayReflectV: Vec, n1: Double = 1, n2: Double = 1 ) object WorldHitCompsModule { trait Service { def hitComps( ray: Ray, hit: Intersection, intersections: List[Intersection] ): IO[GenericError, HitComps] } }
  • 101. LIVE WorldModule WorldHitCompsModule case class HitComps( shape: Shape, hitPt: Pt, normalV: Vec, eyeV: Vec, rayReflectV: Vec, n1: Double = 1, n2: Double = 1 ) object WorldHitCompsModule { trait Service { def hitComps( ray: Ray, hit: Intersection, intersections: List[Intersection] ): IO[GenericError, HitComps] } }
  • 102. LIVE WorldModule PhongReflectionModule case class PhongComponents( ambient: Color, diffuse: Color, reflective: Color ) { def toColor: Color = ambient + diffuse + reflective } object PhongReflectionModule { trait Service { def lighting( pointLight: PointLight, hitComps: HitComps, inShadow: Boolean ): UIO[PhongComponents] } }
  • 103. LIVE WorldModule PhongReflectionModule case class PhongComponents( ambient: Color, diffuse: Color, reflective: Color ) { def toColor: Color = ambient + diffuse + reflective } object PhongReflectionModule { trait Service { def lighting( pointLight: PointLight, hitComps: HitComps, inShadow: Boolean ): UIO[PhongComponents] } }
  • 104. REFLECT THE LIGTHT SOURCE Describe material properties case class Material( color: Color, // the basic color ambient: Double, // ∈ [0, 1] diffuse: Double, // ∈ [0, 1] specular: Double, // ∈ [0, 1] shininess: Double, // ∈ [10, 200] )
  • 105. LIVE PhongReflectionModule WITH LightDiffusion AND LightReflection object PhongReflectionModule { trait Service { } val live: ZLayer[ATModule with LightDiffusionModule with LightReflectionModule, Nothing, PhongReflectionModule] }
  • 106. DRAWING PROGRAM def draw(sceneBundle: SceneBundle): ZIO[CanvasSerializer with RasteringModule with ATModule, Nothing, Array[Byte]]
  • 107. WITH HTTP4S class DrawRoutes[R <: CanvasSerializer with RasteringModule with ATModule] { type F[A] = RIO[R, A] private val http4sDsl = new Http4sDsl[F] {} import http4sDsl._ val httpRoutes: HttpRoutes[F] = HttpRoutes.of[F] { case req @ POST -> Root / "draw" => req.decode[Scene] { scene => (for { bundle <- Http2World.httpScene2World(scene) bytes <- draw(bundle) } yield bytes).foldM { e => InternalServerError(s"something went wrong"), Ok(bytes, "image/png") } } } }
  • 108. AND IN MAIN Provide the layers val world: ZLayer[ATModule, Nothing, WorldModule] = (topologyM ++ hitCompsM ++ phongM) >>> worldModule.live val rastering: ZLayer[ATModule, Nothing, RasteringModule] = (world ++ cameraModule.live) >>> rasteringModule.chunkRasteringModule val full: ZLayer.NoDeps[Nothing, Rastering] = (layers.atM >>> rastering) object Main extends zio.App { override def run(args: List[String]): ZIO[ZEnv, Nothing, Int] = httpProgram.provideLayer(full) }
  • 109. Swapping modules ▸ Red: reflective = 0.9 ▸ Green/white: reflective = 0.6 ▸ Blue: reflective = 0.9, transparency: 1 val world: ZLayer[ATModule, Nothing, WorldModule] = (topologyM ++ hitCompsM ++ phongM) >>> worldModule.opaque
  • 110. Swapping modules ▸ Red: reflective = 0.9 ▸ Green/white: reflective = 0.6 ▸ Blue: reflective = 0.9, transparency: 1 val world: ZLayer[ATModule, Nothing, WorldModule] = (topologyM ++ hitCompsM ++ phongM) >>> worldModule.live
  • 112. CONCLUSION - ZLayer ▸ Dependency graph in the code !
  • 113. CONCLUSION - ZLayer ▸ Dependency graph in the code ! ▸ Type safety, no magic "
  • 114. CONCLUSION - ZLayer ▸ Dependency graph in the code ! ▸ Type safety, no magic " ▸ Compiler helps to satisfy requirements
  • 115. CONCLUSION - ZLayer ▸ Dependency graph in the code ! ▸ Type safety, no magic " ▸ Compiler helps to satisfy requirements ▸ Try it out, and join ZIO Discord channel