ZIO Environment construction - scala

I started experimenting with ZIO, and was trying to run the following highly sophisticated program:
import logger.{Logger, _}
import zio.console._
import zio.{system, _}
object MyApp extends App {
override def run(args: List[String]): ZIO[ZEnv, Nothing, Int] = {
app
.provideSome[Logger](_ => Slf4jLogger.create) //1
.fold(_ => 1, _ => 0)
}
val app: ZIO[Console with system.System with Logger, SecurityException, Unit] =
for {
_ <- info("This message from the logger") //2
maybeUser <- system.env("USER")
_ <- maybeUser match {
case Some(userName) => putStrLn(s"Hello ${userName}!")
case None => putStrLn("I don't know your name")
}
} yield ()
}
(Slf4jLogger is https://github.com/NeQuissimus/zio-slf4j)
If I comment lines //1 and //2 out everything works fine. But in the above form I get a type mismatch error:
Error:(13, 45) type mismatch;
found : logger.Slf4jLogger
required: zio.console.Console with zio.system.System with logger.Logger
.provideSome[Logger](_ => Slf4jLogger.create)
I don't understand the following:
The program required a Console and a System instance in the environment, yet I did not have to .provide it before, when I was not logging. Why? And why do I suddenly need it?
According to the scaladoc, .provideSome Provides *some* of the environment required to run this effect, leaving the remainder R0. For me that means that I don't have to provide the full environment type, I could add the required modules one by one - yet it seems to expect the full ZEnv type, just like .provide - so what's the point?
I cannot instantiate an anonymous class by new Logger with Console.Live with system.System.Live, because the Slf4jLogger has a factory method in the companion object. How can I use this factory method with the other traits?
Since creating a logger instance in Java is kind of effectful, is .provide even the right function to call?
PS: I was able to get this working in a kind of ugly way:
app
.provideSome[ZEnv](_ =>
new Console with Logger with system.System {
override val console = Console.Live.console
override val system = System.Live.system
override val logger = Slf4jLogger.create.logger
}
) //1
.fold(_ => 1, _ => 0)
This compiles and runs, but overriding the mixed in traits' inner members does not seem right...
And it works in exactly the same way with .provide:
app
.provide(
new Console with Logger with system.System {
override val console = Console.Live.console
override val system = System.Live.system
override val logger = Slf4jLogger.create.logger
}
) //1
.fold(_ => 1, _ => 0)
What is going on?

I am afraid you do have to return an instance that implements all the traits you want to provide.
If you look at the example in ZIO's documentation for provideSome, you see that they are doing the exact same thing: They are taking a Console and turn it into a Console with Logging.
/**
* Provides some of the environment required to run this effect,
* leaving the remainder `R0`.
*
* {{{
* val effect: ZIO[Console with Logging, Nothing, Unit] = ???
*
* effect.provideSome[Console](console =>
* new Console with Logging {
* val console = console
* val logging = new Logging {
* def log(line: String) = console.putStrLn(line)
* }
* }
* )
* }}}
*/
For me that means that I don't have to provide the full environment type, I could add the required modules one by one
No. You have to provide an instance of the full environment type to the effect you are wrapping (because it needs that). I think this is because we want to have this checked at compile-time and there is no way (without macros) to generate a "mash-up" stacked environment without spelling out how to do that. There will probably be some macros for that down the road.
just like .provide - so what's the point?
The difference is that with .provide you have to make up that instance of the required environment from scratch without any input. So that as a result, the effect (with your wrapping) no longer requires anything.
Whereas with .provideSome you yourself can request an environment to help you construct the instance you are providing. That environment will be passed into your function. In the example above, they require a Console and augment it to Console with Logging (by using the console instance they are given). As a result, effect.provideSome[Console](...) still requires a Console (whereas written with .provide it would require Nothing).
.provideSome[ZEnv](_ =>
new Console with Logger with system.System {
override val console = Console.Live.console
Since you are using provideSome[ZEnv], you should probably not access the global singletons Console.Live, but take that from the env being passed in:
.provideSome[ZEnv](env =>
new Console with Logger with system.System {
override val console = env.console
The program required a Console and a System instance in the environment, yet I did not have to .provide it before
That is because ZEnv, the default environment already provides these two.
Since creating a logger instance in Java is kind of effectful, is .provide even the right function to call?
Personally, I would ignore that constructing loggers is effectful. It does not seem like something worth tracking. I consider it some basic facility that it is almost a part of class-loading.
If you did want to track the effect, you could do
app
.provideSomeM(env => for {
logger <- UIO(Slf4jLogger.create)
} yield new MyEnvironment(env, logger)
)

Let me try to explain.
If you have a look at what ZEnv is it's an alias for Clock with Console with System with Random with Blocking. So, when you started implementing def run(args: List[String]): ZIO[ZEnv, Nothing, Int] zio already provided you with these capabilities.
Your app variable signature has a return type of zio with environment Console with System with Logger - one thing that stands out is a Logger capability. It's not standard so ZIO can't provide it for you. You have to provide it yourself.
That's what you did using .provideSome[Logger] - you eliminated one of the capabilities from environment requirements making it type compatible with the standard:
type ZEnv = Clock with Console with System with Random with Blocking
type YourEnv = Console with System
type Proof = ZEnv <:< YourEnv

This is a way that I use:
import logger.{Logger, _}
import zio.console._
import zio.{system, _}
object MyApp extends App {
override def run(args: List[String]): ZIO[ZEnv, Nothing, Int] = {
app
.fold(_ => 1, _ => 0)
}
val app: ZIO[Environment, SecurityException, Unit] =
for {
_ <- info("This message from the logger").provide( Slf4jLogger.create) // 1
maybeUser <- system.env("USER")
_ <- maybeUser match {
case Some(userName) => putStrLn(s"Hello ${userName}!")
case None => putStrLn("I don't know your name")
}
} yield ()
}
I provide it directly in the for-comprehension of the app. All the rest you have from the zio.App.

Related

In scala macro, is it possible to execute code after the macro context has aborted?

I'm solving a macro bug that may affects shapeless & singleton-ops for scala 2, both contains the following code to override the implicitNotFound annotation of a particular type symbol:
def setAnnotation(msg: String, annotatedSym : TypeSymbol): Unit = {
import c.internal._
import decorators._
val tree0 =
c.typecheck(
q"""
new _root_.scala.annotation.implicitNotFound("dummy")
""",
silent = false
)
class SubstMessage extends Transformer {
val global = c.universe.asInstanceOf[scala.tools.nsc.Global]
override def transform(tree: Tree): Tree = {
super.transform {
tree match {
case Literal(Constant("dummy")) => Literal(Constant(msg))
case t => t
}
}
}
}
val tree = new SubstMessage().transform(tree0)
annotatedSym.setAnnotations(Annotation(tree))
()
}
The above code will override the error reporting when c.abort() is called, after which this stateful change should be regard as useless, and the change should be reverted ASAP. In fact, since the TypeSymbol is unique within each compiler invocation, failing to do so will cause the remainder of the compilation to behave erratically (see
https://github.com/fthomas/singleton-ops/issues/234 for detail)
To my best knowledge, what I"m asking for seems to be beyond the capability of the macro system. I need to add the clean up code into a thunk which can be called by The context AFTER the top-level implicit not found error has been reported. How should I do this?

Option and null in Scala

If I have the following function:
def getOrNull[T >: Null](f: => T): T = {
try { f } catch { case _: NullPointerException => null }
}
And I want to use it with Option like so:
val r = Option(getOrNull(someString.split("/")(0)))
I get:
Error:(25, 19) Option.type does not take parameters
What is going on, and how can I overcome this?
You might wonder what Option you are referring to.
From sbt console, use //print<tab>:
scala> Option //print
scala.Option // : Option.type
For better context:
package nooption
class Option(arg: String) // some other option on class path
object Option
object Test {
import scala.reflect.internal.util.ScalaClassLoader
def main(args: Array[String]): Unit = println {
//Option(null)
//ScalaClassLoader.originOfClass(classOf[Option])
ScalaClassLoader.originOfClass(classOf[Option$])
}
}
The class name for the companion object has a dollar at the end.
Your IDE might "go to definition."
If you started a REPL at the command line, class files in the current directory are on its class path. If you previously compiled an Option in the default or "empty" package, it will hide scala.Option.
As noted in the comments, this code does compile OK, but you really shouldn't use null in Scala unless you are interfacing with Java.
This is a better way of implementing your code:
val r = Try{ someString.split("/")(0) }.toOption
Try is widely used in Scala so this code is clear to anyone experienced with the language, so there is no need for a separate function.

scala App class DelayedInit hook

trait App extends DelayedInit {
//...
private val initCode = new ListBuffer[() => Unit]
/** The init hook. This saves all initialization code for execution within `main`.
* This method is normally never called directly from user code.
* Instead it is called as compiler-generated code for those classes and objects
* (but not traits) that inherit from the `DelayedInit` trait and that do not
* themselves define a `delayedInit` method.
* #param body the initialization code to be stored for later execution
*/
override def delayedInit(body: => Unit) {
initCode += (() => body)
}
//...
}
object CircuitMain extends App {
// You can write tests either here, or better in the test class CircuitSuite.
Circuit.andGateExample //line in question ?
}
Related Post why-if-i-extend-the-app-trait-in-scala-i-override-the-main-method
I can see that in the comment it is saying it will be called by compiler generated code.
and from the related post, it is saying that the scala compiler will do special things about DelayedInit, what made this DelayedInit trait so special ? is it language related feature? or we can do similar things to other traits as well ? if yes, how to do that.
Was pondering this myself the other day...
Yes, it's a language specific feature - check Section 5.1 "Delayed Initializaton" in the Scala Language Specification:
http://www.scala-lang.org/docu/files/ScalaReference.pdf
You can also confirm this checking out the compiler source code:
https://github.com/scala/scala/blob/946b76ad8b31b1fd74e2f8e1972c4a9159ac690a/src/reflect/scala/reflect/internal/StdNames.scala
// Compiler utilized names
...
val delayedInit: NameType = "delayedInit"
val delayedInitArg: NameType = "delayedInit$body"
And also:
https://github.com/scala/scala/blob/96df73d994097e3318d003ddef00194b711289a3/src/reflect/scala/reflect/internal/Definitions.scala
// classes with special meanings
lazy val StringAddClass = requiredClass[scala.runtime.StringAdd]
lazy val ScalaNumberClass = requiredClass[scala.math.ScalaNumber]
lazy val TraitSetterAnnotationClass = requiredClass[scala.runtime.TraitSetter]
lazy val DelayedInitClass = requiredClass[scala.DelayedInit]
def delayedInitMethod = getMemberMethod(DelayedInitClass, nme.delayedInit)

How can we override the react construct of scala actors?

The usual way of detecting the type of message received in scala actors is by
loop{
react{
case x: String =>
}
}
However, I want to know how can we override this implementation of react construct so that we can do implicit logging of the message that is received.
I am trying to implement a use case mentioned below ->
1. Before a message is matched to any case class, I want to write a log statement on console / file showing the occurance of the message.
2. We can log these messages explicitly by println() / log4j logging . However, I want to design a generic logger for scala actors which will log all the messages sent or received.
Any help in this regard will be helpful.
Thanks in advance
First, be aware that the Scala actors library is being deprecated in favor of Akka. So this answer won't be helpful very long (though the other actors library will continue to be available for a while--and since it's open source potentially forever if people want to maintain it).
Anyway, the react method is defined in scala.actors.Actor. Simply fail to import it, or hide it with your own. Your own what?
Well, the method just takes a PartialFunction[Any,Unit]. So, your should also:
def react(pf: PartialFunction[Any,Unit]): Nothing = { /*how?;*/ Actor.react(/*what?*/) }
You really only have access to the partial function, and you have to defer to Actor.react to do what you want. So you need to wrap pf in another PartialFunction that performs your logging. So you can
val qf = new PartialFunction[Any,Unit] {
def isDefinedAt(a: Any) = pf.isDefinedAt(a)
def apply(a: Any): Unit = {
log(a) // Maybe add more logic to know what a is
pf(a)
}
}
If you want to see messages that come in and get examined but are not actually consumed, you could do more with isDefinedAt also.
So, obviously enough, I hope, /*how?*/ is the above to define (create) qf, and /*what?*/ is just qf.
If you want to know whether a is a case class, the answer is that you cannot (by design). A case class is just syntactic sugar on top of ordinary Scala features; it's just there to save you typing. See, for instance, this question.
However, you can get pretty close by pattern matching for Product and checking whether it has a copy method:
case class M(i: Int)
val a: Any = M(5)
scala> a match {
case p: Product if p.getClass.getMethods.exists(_.getName=="copy") => println("Yes")
case _ => println("No")
}
Yes
If you really want to get fancy, check if copy has the same number and type of parameters as the constructor.
//Following is a code for a logReact Method that does the same thing as react but also logs the message received hope this works for you
import scala.actors.Actor;
import scala.actors.Actor._
trait ActorLogging extends Actor {
def logReact(handler: PartialFunction[Any, Unit]): Nothing = {
val handler2: PartialFunction[Any, Unit] = {
case x =>
println("Inside Logs -- with message recieved -- " + x.toString);
handler.apply(x);
}
super.react(handler2)
}
}
class sumAct extends Actor with ActorLogging {
def act() {
loop {
logReact {
case a: Int =>
println("Inside actor Sum Act Received the message -- " + a)
exit;
}
}
}
}
object ActorLog {
def main(args: Array[String]): Unit = {
var s: sumAct = new sumAct;
s.start();
s ! 1.toInt;
}
}

Syntactic sugar for compile-time object creation in Scala

Lets say I have
trait fooTrait[T] {
def fooFn(x: T, y: T) : T
}
I want to enable users to quickly declare new instances of fooTrait with their own defined bodies for fooFn. Ideally, I'd want something like
val myFoo : fooTrait[T] = newFoo((x:T, y:T) => x+y)
to work. However, I can't just do
def newFoo[T](f: (x:T, y:T) => T) = new fooTrait[T] { def fooFn(x:T, y:T):T = f(x,y); }
because this uses closures, and so results in different objects when the program is run multiple times. What I really need is to be able to get the classOf of the object returned by newFoo and then have that be constructable on a different machine. What do I do?
If you're interested in the use case, I'm trying to write a Scala wrapper for Hadoop that allows you to execute
IO("Data") --> ((x: Int, y: Int) => (x, x+y)) --> IO("Out")
The thing in the middle needs to be turned into a class that implements a particular interface and can then be instantiated on different machines (executing the same jar file) from just the class name.
Note that Scala does the right thing with the syntactic sugar that converts (x:Int) => x+5 to an instance of Function1. My question is whether I can replicate this without hacking the Scala internals. If this was lisp (as I'm used to), this would be a trivial compile-time macro ... :sniff:
Here's a version that matches the syntax of what you list in the question and serializes/executes the anon-function. Note that this serializes the state of the Function2 object so that the serialized version can be restored on another machine. Just the classname is insufficient, as illustrated below the solution.
You should make your own encode/decode function, if even to just include your own Base64 implementation (not to rely on Sun's Hotspot).
object SHadoopImports {
import java.io._
implicit def functionToFooString[T](f:(T,T)=>T) = {
val baos = new ByteArrayOutputStream()
val oo = new ObjectOutputStream(baos)
oo.writeObject(f)
new sun.misc.BASE64Encoder().encode(baos.toByteArray())
}
implicit def stringToFun(s: String) = {
val decoder = new sun.misc.BASE64Decoder();
val bais = new ByteArrayInputStream(decoder.decodeBuffer(s))
val oi = new ObjectInputStream(bais)
val f = oi.readObject()
new {
def fun[T](x:T, y:T): T = f.asInstanceOf[Function2[T,T,T]](x,y)
}
}
}
// I don't really know what this is supposed to do
// just supporting the given syntax
case class IO(src: String) {
import SHadoopImports._
def -->(s: String) = new {
def -->(to: IO) = {
val IO(snk) = to
println("From: " + src)
println("Applying (4,5): " + s.fun(4,5))
println("To: " + snk)
}
}
}
object App extends Application {
import SHadoopImports._
IO("MySource") --> ((x:Int,y:Int)=>x+y) --> IO("MySink")
println
IO("Here") --> ((x:Int,y:Int)=>x*y+y) --> IO("There")
}
/*
From: MySource
Applying (4,5): 9
To: MySink
From: Here
Applying (4,5): 25
To: There
*/
To convince yourself that the classname is insufficient to use the function on another machine, consider the code below which creates 100 different functions. Count the classes on the filesystem and compare.
object App extends Application {
import SHadoopImports._
for (i <- 1 to 100) {
IO(i + ": source") --> ((x:Int,y:Int)=>(x*i)+y) --> IO("sink")
}
}
Quick suggestion: why don't you try to create an implicit def transforming FunctionN object to the trait expected by the --> method.
I do hope you won't have to use any macro for this!