Project Stage | CI | Release | Snapshot | Discord |
---|---|---|---|---|
Direct-Style programming in ZIO based on the Monadless paradigm.
ZIO-Direct allows direct style programming with ZIO. This provides a more powerful alternative to for-comprehensions and a more natural programming style for many applications. Simply add the .run
suffix to any ZIO effect in order to retrieve it's value.
ZIO-Direct works by using by using macros to rewrite sequential code into flatMap-chains. The values resulting in .run
calls from the ZIO effects are not actually awaited. Instead, they are rolled-up into a chain of flatMaps. The above-code is transformed into something like this.
Let's have a look at a non-trivial example.
class Database:
def nextRow(): ZIO[Any, Throwable, Row]
def hasNextRow(): ZIO[Any, Throwable, Boolean]
def lockNextRow(): ZIO[Any, Throwable, Boolean]
object Database:
def open: ZIO[Any, Throwable, Database]
defer {
// Open a database connection
val db = Database.open().run
// See if there is is a next-row
while (db.hasNextRow().run) {
// try to lock, if aquired continue
if (db.lockNextRow().run)
val nextRow = db.nextRow().run
doSomethingWith(nextRow)
else
waitT()
}
}
NOTE: The above database-api is imaginary.
The above code needs to be translated into something like this:
Database.open.flatMap { db =>
def whileFun(): ZIO[Any, Throwable, Unit] =
db.hasNextRow().flatMap { hasNextRow =>
if (hasNextRow)(
db.lockNextRow().flatMap { lockNextRow =>
if (!lockNextRow)
db.nextRow().map(nextRow => doSomethingWith(nextRow))
else
ZIO.succeed(waitT())
}
).flatMap(_ => whileFun())
else
ZIO.unit
}
whileFun()
}
Note that normally this is the exact code that would have to be written to capture such functionality For-comprehensions do not provide a way to do looping and branching so in such cases a combination of flatMaps and recursion is necessary to avoid calling effects unnecessarily.
See the Code of Conduct