I am using scalap to read out the field names of some case classes (as discussed in this question). Both the case classes and the code that uses scalap to analyze them have been compiled and put into a jar file on the classpath.
Now I want to run a script that uses this code, so I followed the instructions and came up with something like
::#!
#echo off
call scala -classpath *;./libs/* %0 %*
goto :eof
::!#
//Code relying on pre-compiled code that uses scalap
which does not work:
java.lang.ClassCastException: scala.None$ cannot be cast to scala.Option
at scala.tools.nsc.interpreter.ByteCode$.caseParamNamesForPath(ByteCode.
scala:45)
at scala.tools.nsc.interpreter.ProductCompletion.caseNames(ProductComple
tion.scala:22)
However, the code works just fine when I compile everything. I played around with additional scala options like -savecompiled, but this did not help. Is this a bug, or can't this work in principle? (If so, could someone explain why not? As I said, the case classes that shall be analyzed by scalap are compiled.)
Note: I use Scala 2.9.1-1.
EDIT
Here is what I am essentially trying to do (providing a simple way to create multiple instances of a case class):
//This is pre-compiled:
import scala.tools.nsc.interpreter.ProductCompletion
//...
trait MyFactoryTrait[T <: MyFactoryTrait[T] with Product] {
this: T =>
private[this] val copyMethod = this.getClass.getMethods.find(x => x.getName == "copy").get
lazy val productCompletion = new ProductCompletion(this)
/** The names of all specified fields. */
lazy val fieldNames = productCompletion.caseNames //<- provokes the exception (see above)
def createSeq(...):Seq[T] = {
val x = fieldNames map { ... } // <- this method uses the fieldNames value
//[...] invoke copyMethod to create instances
}
// ...
}
//This is pre-compiled too:
case class MyCaseClass(x: Int = 0, y: Int = 0) extends MyFactoryTrait[MyCaseClass]
//This should be interpreted (but crashes):
val seq = MyCaseClass().createSeq(...)
Note: I moved on to Scala 2.9.2, the error stays the same (so probably not a bug).
This is a bug in the compiler:
If you run the program inside an ide, for example Intellij IDEA the code is executed fine, however no fields names are found.
If you run it from command line using scala, you obtain the error you mentioned.
There is no way type-safe could should ever compiler and throw a runtime ClassCastException.
Please open a bug at https://issues.scala-lang.org/secure/Dashboard.jspa
Related
I try to get names of all trait a class extends using getInterfaces which returns an array of trait's names. When I manually access each member of the array, the method getName returns simple names like this
trait A
trait B
class C() extends A, B
val c = C()
val arr = c.getClass.getInterfaces
arr(0).getName // : String = A
arr(1).getName // : String = B
However, when I use map function on arr. The resulting array contains a cryptic version of trait's names
arr.map(t => t.getName) // : Array[String] = Array(repl$.rs$line$1$A, repl$.rs$line$2$B)
The goal of this question is not about how to get the resulting array that contains simple names (for that purpose, I can just use arr.map(t => t.getSimpleName).) What I'm curious about is that why accessing array manually and using a map do not yield a compatible result. Am I wrong to think that both ways are equivalent?
I believe you run things in Scala REPL or Ammonite.
When you define:
trait A
trait B
class C() extends A, B
classes A, B and C aren't defined in top level of root package. REPL creates some isolated environment, compiles the code and loads the results into some inner "anonymous" namespace.
Except this is not true. Where this bytecode was created is reflected in class name. So apparently there was something similar (not necessarily identical) to
// repl$ suggest object
object repl {
// .rs sound like nested object(?)
object rs {
// $line sounds like nested class
class line { /* ... */ }
// $line$1 sounds like the first anonymous instance of line
new line { trait A }
// import from `above
// $line$2 sounds like the second anonymous instance of line
new line { trait B }
// import from above
//...
}
}
which was made because of how scoping works in REPL: new line creates a new scope with previous definitions seen and new added (possibly overshadowing some old definition). This could be achieved by creating a new piece of code as code of new anonymous class, compiling it, reading into classpath, instantiating and importing its content. Byt putting each new line into separate class REPL is able to compile and run things in steps, without waiting for you to tell it that the script is completed and closed.
When you are accessing class names with runtime reflection you are seeing the artifacts of how things are being evaluated. One path might go trough REPLs prettifiers which hide such things, while the other bypass them so you see the raw value as JVM sees it.
The problem is not with map rather with Array, especially its toString method (which is one among the many reasons for not using Array).
Actually, in this case it is even worse since the REPL does some weird things to try to pretty-print Arrays which in this case didn't work well (and, IMHO, just add to the confusion)
You can fix this problem calling mkString directly like:
val arr = c.getClass.getInterfaces
val result = arr.map(t => t.getName)
val text = result.mkString("[", ", ", "]")
println(text)
However, I would rather suggest just not using Array at all, instead convert it to a proper collection (e.g. List) as soon as possible like:
val interfaces = c.getClass.getInterfaces.toList
interfaces .map(t => t.getName)
Note: About the other reasons for not using Arrays
They are mutable.
Thet are invariant.
They are not part of the collections hierarchy thus you can't use them on generic methods (well, you actually can but that requires more tricks).
Their equals is by reference instead of by value.
I am writing a Scala macro (Scala 2.11) where I'd like to obtain the tree representing an implicit variable inside the macro using inferImplicitValue, evaluate that syntax tree, and use the value. I have actually done this, but it doesn't seem to work in all circumstances[1]. I constructed a simplified example where it fails.
// a class for implicit evidence
class DemoEvidence(val value: Int)
// define 'foo' method for invoking the macro
object demoModule {
def foo: Int = macro DemoMacros.fooImpl
}
class DemoMacros(val c: whitebox.Context) {
import c.universe._
def fooImpl: Tree = {
val vInt = try {
// get the tree representing the implicit value
val impl = c.inferImplicitValue(typeOf[DemoEvidence], silent = false)
// print it out
println(s"impl= $impl")
// try to evaluate the tree (this is failing)
val eval = c.eval(c.Expr[DemoEvidence](c.untypecheck(impl.duplicate)))
eval.value
} catch {
case e: Throwable => {
// on failure print out the failure message
println(s"Eval failed with: $e\nStack trace:\n${e.printStackTrace}")
0
}
}
q"$vInt" // return tree representing the integer value
}
}
If I compile the above, and then invoke it:
object demo {
implicit val demoEvidence: DemoEvidence = new DemoEvidence(42)
val i: Int = demoModule.foo
}
I see the compilation fail in the following way:
impl= demo.this.demoEvidence
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$compile$1.apply(ToolBoxFactory.scala:275)
...
Full output at:
https://gist.github.com/erikerlandson/df48f64329be6ab9de9caef5f5be4a83
So, you can see it is finding the tree for the declared implicit value demo.this.demoEvidence, but evaluation of that tree is failing. I have seen this basic approach work elsewhere in my project. Not sure what the difference is, and why it fails here.
[1] UPDATE: If the implicit value is defined in a (sub)project, and compiled, and then used exterior to that project, it works as expected. That was the case where this approach is working for me.
So the question is whether that's just a fundamental constraint I have to live with, or if there is some clever workaround, or if this is a "bug" with inferring implicit values inside macros that might be fixed.
UPDATE: I filed a Scala issue for this: https://github.com/scala/scala-dev/issues/353
From the look of the stack trace, the eval is expecting object demo to exist in classfile form for execution, which makes sense given that the value you're trying to compute depends on val demoEvidence which is a member of object demo.
But the eval is happening during the typechecking of object demo so the classfile doesn't exist yet, hence the error. In the version with the implicit value defined in a subproject I imagine the subproject is compiled first, hence the classfiles required for the eval exist and so evaluation proceeds as you were expecting.
New to Scala and looking for pointers to an idiomatic solution, if there is one.
I'd like to have arbitrary user-supplied Scala functions (which are allowed to reference functions/classes I have defined in my code) applied to some data.
For example: I have foo(s: String): String and bar(s: String): String functions defined in my myprog.scala. The user runs my program like this:
$ scala myprog data.txt --func='(s: Str) => foo(bar(s)).reverse'
This would run line by line through the data file and emit the result of applying the user-specified function to that line.
For extra points, can I ensure that there are no side-effects in the user-defined function? If not, can I restrict the function to use only a restricted subset of functions (which I can assure to be safe)?
#kenjiyoshida has a nice gist that shows how to eval Scala code. Note that when using Eval from that gist, not specifying a return value will result in a runtime failure when Scala defaults to inferring Nothing.
scala> Eval("println(\"Hello\")")
Hello
java.lang.ClassCastException: scala.runtime.BoxedUnit cannot be cast to scala.runtime.Nothing$
... 42 elided
vs
scala> Eval[Unit]("println(\"Hello\")")
Hello
It nicely handles whatever's in scope as well.
object Thing {
val thing: Int = 5
}
object Eval {
def apply[A](string: String): A = {
val toolbox = currentMirror.mkToolBox()
val tree = toolbox.parse(string)
toolbox.eval(tree).asInstanceOf[A]
}
def fromFile[A](file: File): A =
apply(scala.io.Source.fromFile(file).mkString(""))
def fromFileName[A](file: String): A =
fromFile(new File(file))
}
object Thing2 {
val thing2 = Eval[Int]("Thing.thing") // 5
}
Twitter's util package used to have util-eval, but that seems to have been deprecated now (and also triggers a compiler bug when compiled).
As for the second part of your question, the answer seems to be no. Even if you disable default Predef and imports yourself, a user can always get to those functions with the fully qualified package name. You could perhaps use Scala's scala.tools.reflect.ToolBox to first parse your string and then compare against a whitelist, before passing to eval, but at that point things could get pretty hairy since you'll be manually writing code to sanitize the Scala AST (or at the very least reject dangerous input). It definitely doesn't seem to be an "idiomatic solution."
This should be possible by using the standard Java JSR 223 Scripting Engine
see https://issues.scala-lang.org/browse/SI-874
(also mentions using scala.tools.nsc.Interpreter but not sure this is still available)
import javax.script.*;
ScriptEngine e = new ScriptEngineManager().getEngineByName("scala");
e.getContext().setAttribute("label", new Integer(4), ScriptContext.ENGINE_SCOPE);
try {
engine.eval("println(2+label)");
} catch (ScriptException ex) {
ex.printStackTrace();
}
I want my Scala code to take a Scala class as input, compile and execute that class. How can I programmatically invoke a Scala compiler? I will be using the latest Scala version, i.e. 2.10.
ToolBox
I think the proper way of invoking the Scala compiler is doing it via Reflection API documented in Overview. Specifically, Tree Creation via parse on ToolBoxes section in 'Symbols, Trees, and Types' talks about parsing String into Tree using ToolBox. You can then invoke eval() etc.
scala.tools.nsc.Global
But as Shyamendra Solanki wrote, in reality you can drive scalac's Global to get more done. I've written CompilerMatcher so I can compile generated code with sample code to do integration tests for example.
scala.tools.ncs.IMain
You can invoke the REPL IMain to evaluate the code (this is also available in the above CompilerMatcher if you want something that works with Scala 2.10):
val main = new IMain(s) {
def lastReq = prevRequestList.last
}
main.compileSources(files.map(toSourceFile(_)): _*)
code map { c => main.interpret(c) match {
case IR.Error => sys.error("Error interpreting %s" format (c))
case _ =>
}}
val holder = allCatch opt {
main.lastReq.lineRep.call("$result")
}
This was demonstrated in Embedding the Scala Interpreter post by Josh Suereth back in 2009.
The class to be compiled and run (in file test.scala)
class Test {
println ("Hello World!")
}
// compileAndRun.scala (in same directory)
import scala.tools.nsc._
import java.io._
val g = new Global(new Settings())
val run = new g.Run
run.compile(List("test.scala")) // invoke compiler. it creates Test.class.
val classLoader = new java.net.URLClassLoader(
Array(new File(".").toURI.toURL), // Using current directory.
this.getClass.getClassLoader)
val clazz = classLoader.loadClass("Test") // load class
clazz.newInstance // create an instance, which will print Hello World.
I made a code change within a Scala class that had been working fine. Upon trying to compile the modification, the compiler spit out the error message, "value to is not a member of Int" relating to this (pre-existing) line of code:
for (i <- 0 to cColumn -1) { ... }
Doing some research, I came across some bug reports on the "to" method - and also that "to" is apparently a method provided within the intWrapper class(?).
So, based upon that info, I started looking at my class's import statements... no such import for intWrapper. (Q: That being the case, how did this ever compile/run in the first place?) What makes this even more interesting (to me) is that when I started to do a global search in the codebase for that import I accidentally terminated the compiler (sbt) session...but when I restarted it, the class compiled just fine. No errors at all. (And no code changes from the previous session)
Anyone have any ideas as to what would cause this intermittent behavior?
NOTES:
1) using Scala 2.10.2 with javac 1.7.0_25
2) the code change to the class had nothing to do with the example functionality, nor did it alter any of the class's imports
Update: Here are the variable declarations:
val meta = rs.getMetaData()
val cColumn = meta.getColumnCount()
EDIT: Per suggestion, here is the test lines (all of them compile fine now):
implicitly[scala.Int => scala.runtime.RichInt]
intWrapper(3) to 4
for (i <- 0 to 33 -1) { /* do something smart */ }
for (i <- 0 to cColumn -1) { ... }
EDIT 2 Here is the full compiler error:
[error] /path/to/src/file/DBO.scala:329: value to is not a member of Int
[error] for (i <- 0 to cColumn -1) {
[error]
That error was repeating ~18 times in the class. (It's a DBO-DB interface layer); where DBO.scala is the file containing the newly modified trait.
I just encountered this same issue. In my case, it was caused by an unnecessary import, like this:
import scala.Predef.String
class Test() {
for (t <- 1 to 3) {}
}
By default, Scala imports all of scala.Predef. Predef extends LowPriorityImplicits, which includes an implicit conversion from Int to RichInt.
to is actually defined on RichInt, so you need this conversion in order to use it. By importing just part of Predef, I lose this conversion. Get rid of the unnecessary import and the error goes away.
how did this ever compile/run in the first place?
By default, the contents of scala.Predef is imported. There you have method intWrapper which produces a RichInt with method to.
You probably have shadowed symbol intWrapper. Does the following work:
implicitly[scala.Int => scala.runtime.RichInt]
or this:
intWrapper(3) to 4
...if not, there lies your problem.
EDIT: So, since you say that compiles, what happens is you replace cColumn with a constant, e.g.
for (i <- 0 to 33 -1) { ... }
? It would also help to post the complete compiler message with indicated line etc.
Without knowing where that error comes from, you might also try to work around it by constructing the Range by hand:
for (i <- Range.inclusive(0, cColumn-1)) { ... }
or
Range.inclusive(0, cColumn-1).foreach { i => ... }