3

I have found an example code for a Scala runtime scripting in answer to Generating a class from string and instantiating it in Scala 2.10, however the code seems to be obsolete for 2.11 - I cannot find any function corresponding to build.setTypeSignature. Even if it worked, the code seems hard to read and follow to me.

How can Scala scripts be compiled and executed in Scala 2.11?

Let us assume I want following:

  • define several variables (names and values)
  • compile script
  • (optional improvement) change variable values
  • execute script

For simplicity consider following example:

I want to define following variables (programmatically, from the code, not from the script text):

val a = 1
val s = "String"

I want a following script to be compiled and on execution a String value "a is 1, s is String" returned from it:

s"a is $a, s is $s"

How should my functions look like?

def setupVariables() = ???

def compile() = ???

def changeVariables() = ???

def execute() : String = ???
Community
  • 1
  • 1
Suma
  • 33,181
  • 16
  • 123
  • 191
  • Note: `build.setTypeSignature` was replaced with `internal.reificationSupport.setInfo`. See also [Changes in Scala 2.11](http://docs.scala-lang.org/overviews/macros/changelog211.html) - paragraph **How to make your 2.10.x macros work in 2.11.0**. – Suma May 13 '15 at 08:51

1 Answers1

3

Scala 2.11 adds a JSR-223 scripting engine. It should give you the functionality you are looking for. Just as a reminder, as with all of these sorts of dynamic things, including the example listed in the description above, you will lose type safety. You can see below that the return type is always Object.

Scala REPL Example:

scala> import javax.script.ScriptEngineManager

import javax.script.ScriptEngineManager


scala> val e = new ScriptEngineManager().getEngineByName("scala")

e: javax.script.ScriptEngine = scala.tools.nsc.interpreter.IMain@566776ad


scala> e.put("a", 1)

a: Object = 1


scala> e.put("s", "String")

s: Object = String


scala> e.eval("""s"a is $a, s is $s"""")

res6: Object = a is 1, s is String`

An addition example as an application running under scala 2.11.6:

import javax.script.ScriptEngineManager

object EvalTest{
  def main(args: Array[String]){
   val e = new ScriptEngineManager().getEngineByName("scala")
   e.put("a", 1)
   e.put("s", "String")
   println(e.eval("""s"a is $a, s is $s""""))
  }
}

For this application to work make sure to include the library dependency.

libraryDependencies +=  "org.scala-lang" % "scala-compiler" % scalaVersion.value
rock-fall
  • 438
  • 2
  • 11
  • This looks promising, however when I run this in my application (not REPL), I get error `scala.reflect.internal.MissingRequirementError: object scala in compiler mirror not found.`. I have all of "scala-reflect", "scala-compiler" and "scala-library" in my build.sbt (and actually I already had the script compilation working using `universe.runtimeMirror`, only variable setting was something I was unable to do). – Suma Apr 03 '15 at 11:53
  • Note: Scripting engine created getEngineByName succeeds, but I get exception when calling the `eval` function on it. – Suma Apr 03 '15 at 12:05
  • I can get rid of the exception by using `e.asInstanceOf[IMain].settings.usejavacp.value = true`, but then I get very strange errors on second script execution (`CaseClassException` when casting `IMain` to `IMain`). My wild guess embedding Scala in JSR-223 style is intended for Java applications, and not for Scala ones? – Suma Apr 03 '15 at 12:52
  • This code is just POC. It will also run in an application. Maybe you can provide your application code. – rock-fall Apr 03 '15 at 16:23
  • I added an example application in addition to the repl code. I think I remember reading somewhere that there were problems under some earlier versions of Scala with the script engine. Maybe try running 2.11.6? – rock-fall Apr 03 '15 at 16:44
  • Unfortunately the example application does not work for me. I have the compiler dependency added in build.sbt. I have tried both 2.11.5 and 2.11.6, and both from IntelliJ IDE and from sbt command line (using sbt 0.13.8), I always get the same exception: [init] error: error while loading Object, Missing dependency 'object scala in compiler mirror', required by ... /// Failed to initialize compiler: object scala in compiler mirror not found. – Suma Apr 03 '15 at 18:31
  • Since I haven't seen this problem its a little difficult to troubleshoot. I found [this](http://stackoverflow.com/questions/23961092/how-to-use-jsr-223-to-get-scala-interpreter-in-sbt-console). Is the exception coming from the e.put? – rock-fall Apr 03 '15 at 19:07
  • Have you tried to run it as a compiled stand alone application because I did find a problem when running from the sbt console. It looks like it is related to the forked JVM as in the above article. If you get the settings from the engine and use embeddedDefaults with a class in your project it should solve the problem like in the article above. Not sure why it is happening in intellij (using Eclipse), might be the same forked JVM problem as with SBT. BTW dont define that probe class in the console. Good luck! – rock-fall Apr 03 '15 at 20:55
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/74457/discussion-between-rock-fall-and-suma). – rock-fall Apr 03 '15 at 21:10