For some reason, intermediate values aren't being printed out in the REPL console (right hand side of the worksheet)
For instance, this is what I have:
object test {
val obj = new MyObject(1)
obj.value
}
class MyObject(x: Int) {
def value = x
}
In the REPL results, I only get the following:
defined module test
.
.
.
defined class MyObject
However, I don't get any of the intermediate results, such as when I evaluate x.value
I would expect something like:
> MyObject#14254345
> 1
after x.value
Any reason why this isn't printing out?
What ended up working for me in this case (and this might be particular to IntelliJ 14, since I've seen it working the other way in Eclipse) is I added the class inside the object block, like this:
object test {
val obj = new MyObject(1)
obj.value
class MyObject(x: Int) {
def value = x
}
}
This forced the REPL instance inside the worksheet to auto-evalute the result and print them out on the right hand side.
To make it work like it does in Eclipse, turn on "eclipse compatibility" mode. This worked for me using IntelliJ IDEA 2016.
Preferences > Language & Frameworks > Scala > Worksheet
Then, check the Use "eclipse compatibility" mode checkbox.
Sorry, I don't have enough reputation to comment so I have to write it here.
If you want to get the result you want, maybe you can try like this.
scala> :paste
// Entering paste mode (ctrl-D to finish)
object test {
val obj = new MyObject(1)
println(obj.value)
}
class MyObject(x: Int) {
def value = x
}
// Exiting paste mode, now interpreting.
defined object test
defined class MyObject
scala> test.obj
1
res4: MyObject = MyObject#1cd072a9
when you paste the code, test and MyObject are not initialized, certainly you can not get any print.
test.obj will cause test to be initialized so will obj, meantime, obj.value also get evaluated. However, if you don't something about it(like print), it's just a pure expression.
Related
This very simple worksheet content demonstrates the issue:
object Test {
println("This does not print!")
add(5, 6)
}
println("This however prints!")
add(5, 6)
def add(a: Int, b: Int): Int = a + b
Results from the above worksheet content are:
defined module Test
This however prints!
res0: Unit = ()
res1: Int = 11
add: add[](val a: Int,val b: Int) => Int
Based on JetBrains official website Scala Worksheets example and every other reliable resource I've found (like Martin Odresky's own examples in Functional Programming in Scala course), I would expect the contents of object Test to execute. My software is:
OS X El Capitan
IntelliJ IDEA 2016.2
SBT Plugin 1.8.0
SBT Version 0.13.12
Scala Plugin 2016.2.1
Scala Version 2.11.8
I was able to evaluate the Scala work sheet by changing the Scala worksheet settings.
change run type to plain (original it was REPL)
You can get to settings by clicking the settings icon on the Scala worksheet.
The scala worksheet executes the contents of the object test{....} if all the code is inside that object. If there is some code outside the object, it will just define that Test object (and not run it).
object Test {
println("This does not print!")
def add(a: Int, b: Int): Int = {print("Sum:" + a + b); a + b}
add(2, 2)
}
// defined the above Test object
Test // executes the Test object
I think this is what you want:
object Test {
println("This does not print!")
add(5, 6)
println("This however prints!")
add(5, 6)
def add(a: Int, b: Int): Int = a + b
}
How the worksheet works is, that if you define an object and nothing defined outside the object scope, it will execute it as Test extends App. Which is what the intellij page displays
If you have any statement outside the object scope, it is then treated as any other object and compiler will initialize it like anything else. This is what you are experiencing.
I'm using Scala toolbox to eval some Scala code for a web interpreter. It is working well, the code looks like this:
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
object Eval {
val toolbox = runtimeMirror(getClass.getClassLoader).mkToolBox()
def eval[T](code: String): T = {
toolbox.eval(toolbox.parse(code)).asInstanceOf[T]
}
}
I can do something like:
Eval.eval[Long]("1 + 1")
and get 2 back. The question comes up when I want to define something:
Eval.eval[Unit]("val yellow = 5")
Eval.eval[Long]("yellow")
I get a not found: value yellow error. How do I define a value that I can use in later evaluations with Scala Toolbox?
For a persistent environment, you can use Scala's REPL directly. See the JSR-223 note at the very bottom of the 2.11 release notes.
import javax.script.ScriptEngineManager
class DummyClass
object Evaluator {
val engine = new ScriptEngineManager().getEngineByName("scala")
val settings = engine.asInstanceOf[scala.tools.nsc.interpreter.IMain].settings
settings.embeddedDefaults[DummyClass]
engine.eval("val x: Int = 5")
val thing = engine.eval("x + 9").asInstanceOf[Int]
}
The need for DummyClass (or really any class you have can substitute for DummyClass) arises from a bit of shenanigans going on here due to SBT and classloader concerns (more details here).
The screenshot of the following tiny scala script shows four breakpoints set.
object WC {
val code = """import org.apache.hadoop.conf.Configuration
// This class performs the map operation, translating raw input into the key-value
class TokenizerMapper extends Mapper[Object,Text,Text,IntWritable] {
"""
def sloc(str: String): Int = {
val x: List[String] = str.split("\\n").map(_.trim).toList.filter { line =>
line.length!=0 && !line.startsWith("import ") && !line.startsWith("/*") && !line.startsWith("//") && !line.equals("{") && !line.equals("}") }
println(x.mkString("\n"))
x.size
}
}
println (WC.sloc(WC.code))
Here are the peculiarities:
only the very last breakpoint - on the "println (WC.sloc(WC.code))" - is actually respected. The others are ignored
However, I can step through the other three lines in the debugger
I am wondering if others have discovered any "pattern" to how to get the scala debugger to respect the breakpoints. OK we know that the scala plugin is buggy - it is here a matter of trying to get the "most" out of what we have.
I am using the latest IJ ULtimate 12.1.6.
In order for the debugger to work properly IJ unfortunately needs a CLASS to be available - not just the Object. This may have been fixed in 13.
Is it possible to configure a Scala interpreter (tools.nsc.IMain) so that it "forgets" the previously executed code, whenever I run the next interpret() call?
Normally when it compiles the sources, it wraps them in nested objects, so all the previously defined variables, functions and bindings are available.
It would suffice to not generate the nested objects (or to throw them away), although I would prefer a solution which would even remove the previously compiled classes from the class loader again.
Is there a setting, or a method, or something I can overwrite, or an alternative to IMain that would accomplish this? I need to be able to still access the resulting objects / classes from the host VM.
Basically I want to isolate subsequent interpret() calls without something as heavy weight as creating a new IMain for each iteration.
Here is one possible answer. Basically there is method reset() which calls the following things (mostly private, so either you buy the whole package or not):
clearExecutionWrapper()
resetClassLoader()
resetAllCreators()
prevRequests.clear()
referencedNameMap.clear()
definedNameMap.clear()
virtualDirectory.clear()
In my case, I am using a custom execution wrapper, so that needs to be set up again, and also imports are handled through a regular interpret cycle, so either add them again, or—better—just prepend them with the execution wrapper.
I would like to keep my bindings, they are also gone:
import tools.nsc._
import interpreter.IMain
object Test {
private final class Intp(cset: nsc.Settings)
extends IMain(cset, new NewLinePrintWriter(new ConsoleWriter, autoFlush = true)) {
override protected def parentClassLoader = Test.getClass.getClassLoader
}
object Foo {
def bar() { println("BAR" )}
}
def run() {
val cset = new nsc.Settings()
cset.classpath.value += java.io.File.pathSeparator + sys.props("java.class.path")
val i = new Intp(cset)
i.initializeSynchronous()
i.bind[Foo.type]("foo", Foo)
val res0 = i.interpret("foo.bar(); val x = 33")
println(s"res0: $res0")
i.reset()
val res1 = i.interpret("println(x)")
println(s"res1: $res1")
i.reset()
val res2 = i.interpret("foo.bar()")
println(s"res2: $res2")
}
}
This will find Foo in the first iteration, correctly forget x in the second iteration, but then in the third iteration, it can be seen that the foo binding is also lost:
foo: Test.Foo.type = Test$Foo$#8bf223
BAR
x: Int = 33
res0: Success
<console>:8: error: not found: value x
println(x)
^
res1: Error
<console>:8: error: not found: value foo
foo.bar()
^
res2: Error
The following seems to be fine:
for(j <- 0 until 3) {
val user = "foo.bar()"
val synth = """import Test.{Foo => foo}
""".stripMargin + user
val res = i.interpret(synth)
println(s"res$j: $res")
i.reset()
}
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