Skip to content

Commit

Permalink
improvements to composeability #bruce #bill #james #time 1h
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesward committed Jul 24, 2024
1 parent ef76e65 commit a10d4b6
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 39 deletions.
19 changes: 13 additions & 6 deletions Chapters/05_Testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,11 @@ import zio.*
class Material(val brittleness: Int)

object Material:
val wood = ZLayer.succeed(Material(brittleness = 5))
val plastic = ZLayer.succeed(Material(brittleness = 10))
val wood =
ZLayer.succeed(Material(brittleness = 5))
val plastic =
ZLayer
.succeed(Material(brittleness = 10))
```

Different types of `Saw` and `Nailer` each have an `intensity` that relates it to `Material.brittleness`.
Expand All @@ -207,14 +210,18 @@ import zio.Console.*
class Saw(val intensity: Int)

object Saw:
val hand = ZLayer.succeed(Saw(intensity = 4))
val robotic = ZLayer.succeed(Saw(intensity = 8))
val hand =
ZLayer.succeed(Saw(intensity = 4))
val robotic =
ZLayer.succeed(Saw(intensity = 8))

class Nailer(val intensity: Int)

object Nailer:
val hand = ZLayer.succeed(Nailer(intensity = 4))
val robotic = ZLayer.succeed(Nailer(intensity = 11))
val hand =
ZLayer.succeed(Nailer(intensity = 4))
val robotic =
ZLayer.succeed(Nailer(intensity = 11))
````

The test takes a `Material` and checks it against a `Saw` and a `Nailer`:
Expand Down
18 changes: 11 additions & 7 deletions Chapters/06_Failure.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ import zio.*
case object FailObject

object FailException extends Exception:
override def toString: String = "FailException"
override def toString: String =
"FailException"

def failureTypes(n: Int) =
n match
Expand Down Expand Up @@ -146,7 +147,8 @@ import zio.Console.*

def shortCircuit(lim: Int) =
defer:
printLine(s"-- shortCircuit($lim) --").run
printLine(s"-- shortCircuit($lim) --")
.run
val r1 = testLimit(0, lim).run
printLine(s"-> n: $lim, r1: $r1").run
val r2 = testLimit(1, lim).run
Expand Down Expand Up @@ -406,10 +408,10 @@ If you try to catch failures from `temperatureAppComplete` by running the follow

```scala 3 mdoc:fail
def compilerError =
temperatureAppComplete.catchAll:
case ex: GpsException =>
ZIO.succeed:
"This cannot happen"
temperatureAppComplete.catchAll:
case ex: GpsException =>
ZIO.succeed:
"This cannot happen"
```

The compiler reports that we included unusable code.
Expand All @@ -427,7 +429,9 @@ import zio.Console.*

def check(t: Temperature) =
defer:
printLine("Checking Temperature").orDie.run
printLine("Checking Temperature")
.orDie
.run
if t.degrees > 0 then
ZIO
.succeed:
Expand Down
80 changes: 54 additions & 26 deletions Chapters/07_Composability.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ These concepts and their competing solutions will be expanded on and contrasted
In this chapter, we use several pre-defined functions.
The implementations are deliberately hidden to highlight the surprising nature of executing Effects and to maintain focus on composability.

(We start by showing composability with all these other non-ZIO Scala data types.)

## Universal Composability

```scala 3 mdoc:invisible
Expand Down Expand Up @@ -328,33 +330,36 @@ trait File extends AutoCloseable:
def contains(searchTerm: String): Boolean
def write(entry: String): Try[String]
def summaryFor(searchTerm: String): String
def sameContent(other: File): Boolean
def content(): String

def sameContents(
files: List[File]
): Boolean =
println:
"side-effect print: comparing content"

files
.tail
.forall(
_.content() == files.head.content()
)

def openFile(path: String) =
new File:
var contents: List[String] =
List("Medical Breakthrough!")
println("File - OPEN")
println(s"File - OPEN: $path")

override def content() =
path match
case "file1.txt" | "file2.txt" |
"summaries.txt" =>
"file3.txt" | "summaries.txt" =>
"hot dog"
case _ =>
"not hot dog"

override def sameContent(
other: File
): Boolean =
println(
"side-effect print: comparing content"
)
content() == other.content()

override def close =
println("File - CLOSE")
println(s"File - CLOSE: $path")

override def contains(
searchTerm: String
Expand Down Expand Up @@ -420,6 +425,7 @@ Instead, we use `ZIO.fromAutoCloseable`:
import zio.*
import zio.direct.*

// TODO explain that fromAutoClosable takes a ZIO, thus the ZIO.succeed
def openFileZ(path: String) =
ZIO.fromAutoCloseable:
ZIO.succeed:
Expand Down Expand Up @@ -449,20 +455,20 @@ import zio.*
import zio.direct.*

import scala.util.Using
import java.io.FileReader

val staticScoped =
Using(openFile("file1.txt")):
file1 =>
Using(openFile("file2.txt")):
file2 =>
println:
file1.sameContent(file2)

def run =
defer:
staticScoped
.ignore
Using(openFile("file1.txt")):
file1 =>
Using(openFile("file2.txt")):
file2 =>
Using(openFile("file3.txt")):
file3 =>
sameContents:
List(file1, file2, file3)
.get
.get
.get
```

You can see that each new file means an additional level of code nesting.
Expand All @@ -477,13 +483,35 @@ def run =
defer:
val file1 = openFileZ("file1.txt").run
val file2 = openFileZ("file2.txt").run
printLine:
file1.sameContent(file2)
.run
val file3 = openFileZ("file3.txt").run
sameContents:
List(file1, file2, file3)
```

The Effect Oriented code remains flat.

Try with resources only works with structured code, not dynamic values.

```scala 3 mdoc:runzio
import zio.*
import zio.direct.*
import zio.Console.*

def run =
defer:
val fileNames =
List(
"file1.txt",
"file2.txt",
"file3.txt",
)

val files =
ZIO.foreach(fileNames)(openFileZ).run

sameContents(files)
```

## Try

Now let's write to a `File`.
Expand Down

0 comments on commit a10d4b6

Please sign in to comment.