Created
September 9, 2022 19:59
-
-
Save kitlangton/5b1d7b9a14a51055d9071cfc6fdb478d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import zio.{RuntimeFlags => _, _} | |
import scala.annotation.implicitNotFound | |
// # ANNOUNCEMENTS | |
// - NEXT WEEK (Friday, 16th) : Akka to ZIO Demo | |
// - NEXT, NEXT WEEK (Friday, 23rd): Akka to ZIO Panel | |
// # ZIO API Design Techniques | |
// 1. Partial Type Application | |
// - Partial application of type parameters | |
object PartialTypeApplication extends ZIOAppDefault { | |
final case class MainService(yeller: Yeller) { | |
def run: Task[Unit] = | |
yeller.yell("HELLO!") | |
} | |
object MainService { | |
val layer = ZLayer.fromFunction(MainService.apply _) | |
} | |
final case class SoreThroatError(severity: Int) extends Throwable | |
trait Yeller { | |
def yell(message: String): IO[SoreThroatError, Unit] | |
} | |
object Yeller { | |
val live = ZLayer.fromFunction(YellerLive.apply _) | |
// Accessors | |
def yell(message: String): ZIO[Yeller, SoreThroatError, Unit] = | |
ZIO.serviceWithZIO[Yeller](_.yell(message)) | |
} | |
final case class YellerLive() extends Yeller { | |
override def yell(message: String): IO[SoreThroatError, Unit] = | |
if (message.length > 25) ZIO.fail(SoreThroatError(10)) | |
else ZIO.debug(message.toUpperCase) | |
} | |
val program = serviceWithZIO[Yeller](_.yell("Hello World!")) | |
def serviceWithZIOBad[Service: Tag, R, E, A](f: Service => ZIO[R, E, A]): ZIO[R with Service, E, A] = | |
ZIO.service[Service].flatMap(service => f(service)) | |
// GOOD DOCS | |
def serviceWithZIO[Service]: ServiceWithZIOPartiallyApplied[Service] = | |
new ServiceWithZIOPartiallyApplied[Service] | |
final class ServiceWithZIOPartiallyApplied[Service](private val dummy: Boolean = false) extends AnyVal { | |
def apply[R, E, A](f: Service => ZIO[R, E, A])(implicit tag: Tag[Service]): ZIO[R with Service, E, A] = | |
ZIO.service[Service].flatMap(service => f(service)) | |
} | |
val run = program.provide(Yeller.live) | |
} | |
// 2. Implicit Evidence | |
// - Defining Methods on only specific subtypes of a DSL (<:<) | |
// - Custom Evidence with Nicer Errors (IsSubtypeOf) | |
// - Implicit Evidence preventing Redundancies (CanFail) | |
object ImplicitEvidence extends ZIOAppDefault { | |
val stringZIO: UIO[String] = | |
ZIO.succeed("HELLO!") | |
val optionalStringZIO: IO[Nothing, Option[String]] = | |
ZIO.succeed(Option("HELLO!")) | |
val boomingZIO: IO[Error, Nothing] = | |
ZIO.fail(new Error("BOO")) | |
val run = | |
boomingZIO.orElseSucceed("HELLO").debug | |
} | |
@implicitNotFound( | |
"\nThis operator requires that the output type be a subtype of ${Sub}\nBut the actual type was ${Sup}." | |
) | |
trait IsSubtypeOf[-Sub, +Sup] { | |
def widen(sub: Sub): Sup | |
} | |
object IsSubtypeOf { | |
implicit def duh[A]: IsSubtypeOf[A, A] = new IsSubtypeOf[A, A] { | |
override def widen(sub: A): A = sub | |
} | |
} | |
final case class Box[+A](value: A) { | |
def get[B](implicit ev: A => Option[B]): B = | |
ev(value).get | |
} | |
object Box { | |
implicit final class BoxOps[+A](private val self: Box[Option[A]]) extends AnyVal { | |
def get: A = self.value.get | |
} | |
} | |
object BoxExample extends App { | |
// A >>> B & A | |
// B | |
val boxOption: Box[Some[String]] = Box(Some("HELLO")) | |
val boxString: Box[String] = Box("Hello") | |
val result: String = boxOption.get | |
println(result) | |
} | |
// 3. Delimited Danger | |
// - Capability | |
object DelimitedDanger extends App { | |
val sayHowdy = Console.printLine("Howdy!") | |
trait Ref[A] { | |
def set(a: A): ZIO[Any, Nothing, Unit] | |
def unsafe: UnsafeAPI = ??? | |
trait UnsafeAPI { | |
def get()(implicit unsafe: Unsafe): A | |
def set(a: A)(implicit unsafe: Unsafe): Unit | |
} | |
} | |
val ref: Ref[Int] = ??? | |
// ref.unsafeSet(2) | |
def unsafeUpdate[A](ref: Ref[A])(f: A => A)(implicit unsafe: Unsafe): Unit = { | |
val oldValue: A = ref.unsafe.get() | |
ref.unsafe.set(f(oldValue)) | |
} | |
Unsafe.unsafe { implicit unsafe => | |
ZIO.succeed(unsafeUpdate(ref)(_ + 10)) | |
} | |
Unsafe.unsafe { implicit unsafe => | |
Runtime.default.unsafe | |
.run(sayHowdy) | |
.getOrThrowFiberFailure() | |
} | |
} | |
// 4. Companion Object Idioms | |
// - constructors / higher-arity combinators | |
// - example using Coord |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment