Skip to content

Instantly share code, notes, and snippets.

@kitlangton
Created September 9, 2022 19:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kitlangton/5b1d7b9a14a51055d9071cfc6fdb478d to your computer and use it in GitHub Desktop.
Save kitlangton/5b1d7b9a14a51055d9071cfc6fdb478d to your computer and use it in GitHub Desktop.
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