zio / zio-direct Goto Github PK
View Code? Open in Web Editor NEWDirect-Style Programming for ZIO
Home Page: https://zio.dev/zio-direct
Direct-Style Programming for ZIO
Home Page: https://zio.dev/zio-direct
If I turn these on:
scalacOptions := Seq(
"-Wunused:locals",
"-Xfatal-warnings",
)
And have a defer
that returns a concrete value like:
defer:
ZIO.debug("hello, world").run
()
I get:
[error] 6 | defer:
[error] | ^
[error] | unused local definition
Reproducer: https://github.com/jamesward/zio-direct-bug-unused
I was converting some code:
val oldStyle =
for
_ <- printLine("Hi")
_ <- ZIO.fail("Error!")
yield ()
into
val directStyle =
defer {
printLine("Hi").run
ZIO.fail("Error!").run
}
and got this error message:
missing arguments for method apply in trait deferCall
defer {
Is there a fundamental reason why we cannot return ZIO
s with a Nothing
result inside defer
blocks?
If so, is there a way we could provide better error messages in this situation?
There are some great custom compilation error messages in this library, so I was surprised when I hit this one.
It took me a while to figure out what was actually causing the problem.
for
loops in Scala 3 (and 2.x) support guards, however the following does not compile:
def getNums(): UIO[List[Int]] = ZIO.succeed(List(1, 2, 3))
def printNum(n: Int): UIO[Unit] = ZIO.succeed(println(n))
defer {
for {
n <- getNums().run
if n % 2 == 0
} printNum(n).run // Error: While expanding a macro, a reference to parameter n
} // was used outside the scope where it was defined
It seems it has something to do with how guards are desugared, the following also doesn't compile:
defer {
getNums().run.withFilter(n => n % 2 == 0).foreach(n => printNum(n).run)
}
whereas replacing withFilter
with filter
successfully compiles.
In the issue #16 it was discovered that sometimes the presence of a 2nd overloaded method with an extra argument can sometimes "trick" Scala 2 into thinking a correct macro-method is correct.
It was discovered that when you add a 2nd "dummy method" for example:
def defer[T](value: T): ZIO[_, _, _] = macro core.Macro.deferImpl[T]
def defer[T](regex: Something)(value: T): ZIO[_, _, _] = ??? // dummy method
The
Something
class can be anything. I tried java.util.Regex which has nothing to do with anything. Note that the 2nd value can also be of type regex and that the 2nd thing does not even need to be a macro.
In order to do this:
val out =
defer {
val i = Ref.make(0).run
while (i.get.run < 3)
i.getAndUpdate(i => i + 1).run
i.get.run
}
The following above code that normally throws a "macro has not been expanded" error will somehow work.
This is shown in the following branch.
https://github.com/zio/zio-direct/tree/crazy-macro-expansion-error
There are other scenarios where "macro has not been expanded" will occur. for example, if you have a macro the wrong number of arguments:
val out =
defer({
val i = Ref.make(0).run
while (i.get.run < 3)
i.getAndUpdate(i => i + 1).run
i.get.run
}, null) // add extra 'null' argument
Need to watch out for potential similar issues and think about mitigations.
To improve the ergonomics of error handling, it would be nice if we could eliminate some union types from the error channel when explicitly handled in a catch block. Maybe we can simulate the symantics of ZIO.catchSome
and ZIO.die
:
import zio.*
import zio.direct.*
case class ID()
case class Person()
case class ParseError()
case class DBError()
def parseId(s: String): IO[ParseError, ID] = ???
def getPerson(id: ID): IO[DBError, Person] = ???
val t: IO[DBError, Person] = defer {
try {
val id = parseId("1").run
getPerson(id).run
} // ZIO[Any, DBError | ParseError, Person]
catch {
case v: ParseError => Person() // eliminate ParseError we return a subtype of Person (simulates ZIO.catchSome)
case v: ParseError => ZIO.die(???) // alternatively, terminate the fiber with a defect
}
}
The following code triggers a 'Detected the use of a mutable collection inside a defer clause.', but I don't think it should lead to any issues.
defer {
val text = ZIO.succeed("1,2,3").run
val values = text.split(",").toList
ZIO.foreach(values)(v => zio.Console.printLine(v))
}
It would be nice to add ScalaJS 1.x support
Hi, I see the readme says that the below code doesn't work
for {
textA <- read(fileA)
// Not a possible syntax
if (fileA.contains("some string")) {
textB <- read(fileB)
_ <- write(fileC, textA + textB)
}
} yield ()
However it seems that the code below works:
val o1 = Option(1)
val o2 = Option(1)
// condition in monadic DSL
for {
a <- o1
_ <- if true then o1 else o2
} yield ()
// while loop in monadic DSL
for {
a <- o1
_ <- Option(while (true) {})
} yield ()
so it seems that control structure is actually supported in the monadic DSL?
Want to be able to optionally use scalafmt to format code if it is on the path. This is indispensable for .info
calls etc... but want to make this optional. Also, don't want to directly compile anything that has to do with scalafmt directly because it has a nasty tendency to spew hundreds of irrelevant protobuff errors. The ideal way to do this would be to create an upstream library that does what Quill's ScalafmtFormat class does. Essentially have a generic FmtUtils library in the ZIO namespace that does basically what quill-util does.
I added a branch to how how Scalafmt could be pulled in directly (https://github.com/zio/zio-direct/tree/pull-in-scalafmt-directly) and it successfully copiles but if anything is wrong with the compile dozens of protobuff errors will spew to the console. Therefore I do not want to use that branch.
val out =
defer {
val bar = ZIO.succeed("foo").run
unsafe {
"bar"
}
}
Expected out to be of type ZIO[Any, Throwable, String]
but is ZIO[Any, Throwable, Any]
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.