6
votes

Why is it faster to call external scala compiler than use the runtime interpreter library? In the code below it takes almost 2s to warm up the interpreter.

val out = new PrintStream(new FileOutputStream("/dev/null"))
val flusher = new java.io.PrintWriter(out)
val interpret = {
   val settings = new scala.tools.nsc.GenericRunnerSettings(println _)
   settings.usejavacp.value = true
   new scala.tools.nsc.interpreter.IMain(settings, flusher)
}
interpret.interpret(" ") //   <-- warming up
interpret.interpret(" Hello World ")

In the other hand, when running Scala compiler from command line like in a shell session:

scala HelloWorld.scala

it takes less than 0.5s to print a Hello World.

I am trying to parse+execute some Java, Scala or similar code given in a string during runtime (it is a script interpreter, i.e. it will be run only one time during my app execution). Scala code would be better obviously, but only if it can be as fast as the Java option. Is there any faster alternative than nsc.interpreter and external compiler to execute code from a string at runtime? The best I could found was Janino; it is faster than Scala compiler and does not require the JDK (a very interesting feature).

As a last resource, how fast are Java Scripting Engines compared to a reflected or bytecode-compiled Java code? I found that, at least, they can be compiled: Compiling oft-used scripts.



Chosen solution: runtimecompilescala.

1
Can't you run the warm up code asynchronously at an earlier moment in your program?0__
What do you mean by "from command line"? From the REPL? There it is clear why it is faster: All needed classes are already loaded.kiritsuku
@ 0__ : Good idea, but I can't. It is an interpreter of small scripts. The faster the overall start up, the better.user445107
@sschaef: No REPL, just the interpreter/compiler (or other name it may have I don't know exactly). Question edited.user445107
Maybe it has something to do with how much stuff you have in your classpath...ghik

1 Answers

1
votes

There are many things left unstated (like memory settings), but you're comparing apples and oranges.

The command-line script runner is not a REPL session; instead, it wraps your code in a simple object with a main method, compiles and runs that.

By contrast, each interpreted line (or compilable thing) in the REPL is wrapped in an object (with the session history imported so you can refer to past results).

Even modulo REPL start-up, this has performance consequences, see this issue.

The simple wrap-it logic for the script runner is built into the parser. Here is how the script runner runs the compilation. Or, it looks like this is how -e is handled.

Edit: your comment to your question implies that you really want fsc compile server behavior. Fire up fsc and use the compile client.