56

Can Scala be used to script a Java application?

I need to load a piece of Scala code from Java, set up an execution scope for it (data exposed by the host application), evaluate it and retrieve a result object from it.

The Scala documentation shows how easy it is to call compiled Scala code from Java (because it gets turned into to regular JVM bytecode).

But how can I evaluate a Scala expression on the fly (from Java or if that is easier, from within Scala) ?

For many other languages, there is the javax.scripting interface. Scala does not seem to support it, and I could not find anything in the Java/Scala interoperability docs that does not rely on ahead-of-time compilation.

Thilo
  • 257,207
  • 101
  • 511
  • 656
  • Scala 2 https://stackoverflow.com/questions/73911801/how-can-i-run-generated-code-during-script-runtime Scala 3 https://stackoverflow.com/questions/70945320/how-to-compile-and-execute-scala-code-at-run-time-in-scala3 – Dmytro Mitin Oct 01 '22 at 15:36

6 Answers6

66

it's now 2011, and you can do so with scala.tools.nsc.Interpreter see http://blog.darevay.com/2009/01/remedial-scala-interpreting-scala-from-scala/

use scala.tools.nsc.interpreter

ninjagecko
  • 88,546
  • 24
  • 137
  • 145
  • 8
    That is not a "third-party" package, it's part of the Scala language implementation proper. – Randall Schulz May 28 '11 at 21:16
  • 7
    It's worth pointing out that the interpreter is contained in the Scala compiler, not the public facing standard library API, and is therefore subject to change. The linked blog was written for Scala version 2.8. As of version 2.9, one must replace `scala.tools.nsc.Interpreter` with `scala.tools.nsc.interpreter.IMain`. The rest of the code in the blog should work the same. – Kipton Barros Jun 25 '11 at 21:20
  • @Kipton and `nsc.interpreter.ISettings` as well I think. Unfortunately I and others are getting values ClassCastExceptions: http://stackoverflow.com/questions/6367393/scala-foo-cannot-be-cast-to-foo (when I tried to test out my answer recently) and http://stackoverflow.com/questions/6164138/scala-as-scripting-language/6164608#6164608 – ninjagecko Jun 26 '11 at 06:52
  • you're having problems with the classloader? My workaround is to set the *Java* classpath, and create the interpreter with "usejavacp". Also, you might find the answer here relevant: http://stackoverflow.com/questions/4121567/embedded-scala-interpreter-inherits-parent-classpath – Kipton Barros Jun 27 '11 at 06:06
  • 4
    As of 2.10, you can build source trees and compile them with scala.tools.reflect.ToolBox#eval. See slide 35 of http://scalamacros.org/talks/2012-04-28-MetaprogrammingInScala210.pdf – Bill Feb 10 '13 at 18:17
  • 4
    404: Page Not Found – Det Feb 10 '18 at 13:04
  • 1
    it's 2018 going on 2019. – som-snytt Oct 16 '18 at 22:08
  • importing `scala.tools.nsc.Interpreter` gives a deprecation warning. Link is dead. It is 2022.... sorry, have to downvote. Please fix this answer. – Z4-tier Feb 14 '22 at 14:09
  • @Z4-tier feel free to let us know if `interpreter` is deprecated – ninjagecko Feb 15 '22 at 15:18
  • Scala 3 [dotty.tools.repl.ScriptEngine](https://javadoc.io/static/org.scala-lang/scala3-compiler_3/3.2.0/dotty/tools/repl/ScriptEngine.html), Scala 2 [scala.tools.nsc.interpreter.shell.Scripted](https://www.scala-lang.org/api/2.13.9/scala-compiler/scala/tools/nsc/interpreter/shell/Scripted.html) – Dmytro Mitin Sep 30 '22 at 10:19
53

Scala is not a scripting language. It may look somewhat like a scripting language, and people may advocate it for that purpose, but it doesn't really fit well within the JSR 223 scripting framework (which is oriented toward dynamically typed languages). To answer your original question, Scala does not have an eval function just like Java does not have an eval. Such a function wouldn't really make sense for either of these languages given their intrinsically static nature.

My advice: rethink your code so that you don't need eval (you rarely do, even in languages which have it, like Ruby). Alternatively, maybe you don't want to be using Scala at all for this part of your application. If you really need eval, try using JRuby. JRuby, Scala and Java mesh very nicely together. It's quite easy to have part of your system in Java, part in Scala and another part (the bit which requires eval) in Ruby.

Daniel Spiewak
  • 54,515
  • 14
  • 108
  • 120
  • 4
    +1 Scala does support being run from a text file like a scripting language, but it isn't a scripting language. It sounds like the author is interested in providing a scripting interface to his app, which JavaScript, Groovy or Lua would be better suited for. – Kevin Peterson Jul 26 '09 at 20:31
  • Okay, I am going to grudgingly accept this answer. Too bad, since the Scala docs seem to highlight their interpreter as a significant feature. One would think that this would be using some kind of "eval" under the hood. Apparently not. – Thilo Aug 04 '09 at 07:37
  • 5
    The interpreter is not a language feature, it's just part of the tool set. Look at Haskell as a good example. GHC Haskell provides the `ghc` tool, which is the compiler, and `ghci`, which is the interactive shell. It's an "interpreter" just like Scala's REPL, but there is really no way to use it within a Haskell function. As mentioned previously, to allow this would be horribly unsafe (type-wise) and not in line with the language as a whole. – Daniel Spiewak Aug 04 '09 at 14:08
  • This is not entirely true. GHI exposes much of it's functionality as an api, which is unfortunately not very easy to use. There are packages that help you with this: http://hackage.haskell.org/package/hint – srparish Jun 16 '11 at 04:36
  • 2
    @woky And the answer states pretty clearly: " Scala does not have an eval function just like Java does not have an eval". The answerer did not say what he *thinks* about Scala, he said that Scala is not a scripting language - which it is not. And that's a fact. Ask a community of JS devs how to do inline assembly for the device driver that you're building in Javascript - and you'll get the same answer: "you're using the wrong language". And that would not be an opinion about inline assembly or device drivers. – Ruslan Sep 17 '15 at 17:11
  • @woky agreed, I want eval so I can have my scala be able to write itself the same way javascript can write itself(since javascript is able to stringify its own code as well as eval it). With minor changes scala could be javascript on steroids(multithreaded). – Dmytro Jul 20 '16 at 02:42
  • 1
    "Such a function wouldn't really make sense for either of these languages given their intrinsically static nature."| I think this sentence needs more justification. I don't see any intrinsic problem in performing an eval on a snippet of text that contains code in a statically-typed language. – user118967 Mar 02 '18 at 19:03
  • 1
    This answer may have been more true ten years ago, but it's called "Scala" because the language (as such) is scalable, from small scripts to apps. The tooling could be improved for evaluation in dynamic contexts, but scripting (as such) is clearly part of its mandate. – som-snytt Oct 16 '18 at 22:14
22

Scala has added official support to JSR-223 in 2.11 (https://issues.scala-lang.org/browse/SI-874).

So if you still need it after thinking about the considerations made in the currently accepted answer from Daniel Spiewak (about rethinking in a way it is not needed), this should be the official alternative.

Oswaldo
  • 513
  • 5
  • 13
16

I am not sure, if this is a good way, but I solved this problem with using toolbox.parse and toolbox.eval

To have an eval in Scala you have to:

  1. Import scala-reflect

libraryDependencies += "org.scala-lang" % "scala-reflect" % "2.11.7"

  1. Use eval from toolbox:

  import scala.reflect.runtime.currentMirror
  import scala.tools.reflect.ToolBox
  val toolbox = currentMirror.mkToolBox()

  val as = "2*(2+3)"
  val compe = toolbox.eval(toolbox.parse(as))

  println(compe.getClass) // prints class java.lang.Integer
  println(compe) // prints 10

ZhekaKozlov
  • 36,558
  • 20
  • 126
  • 155
gun
  • 1,046
  • 11
  • 22
16

You can emulate "eval" by taking scala code, wrapping it in a class, compiling that class, using reflection to create a new instance, and then calling it. It's a little involved, and the scala compiler is very slow (on the order of 2 seconds) to initialize, but it works fine.

There's a library for it here, called "util-eval": https://github.com/twitter/util/

The code in question lives here: https://github.com/twitter/util/blob/master/util-eval/src/main/scala/com/twitter/util/Eval.scala

It works like this:

val sum = Eval[Int]("1 + 1")
// sum will be 2
Robey Pointer
  • 231
  • 2
  • 7
  • Nice! Although the above syntax still works, it now prints a warning: "object Eval in package util is deprecated: use a throw-away instance of Eval instead." The new recommended code is: `val i: Int = new Eval()("1 + 1")`. See Eval.scala's different `apply()` functions for variations (reading from files or InputStreams). – Mike Morearty Oct 08 '14 at 16:07
  • The last version is 6.43.0 (April 2017) https://github.com/twitter/util/blob/util-6.43.0/util-eval/src/main/scala/com/twitter/util/Eval.scala `libraryDependencies += "com.twitter" % "util-eval_2.12" % "6.43.0"` – Dmytro Mitin Oct 06 '22 at 22:05
  • Util-eval 6.43.0 works till Scala 2.12.12, after that `java.lang.NoSuchMethodError: com.twitter.util.Eval$EvalSettings.bootclasspath()Lscala/tools/nsc/settings/AbsSettings$AbsSetting;` `new Eval().apply[Int]("1 + 1")` https://scastie.scala-lang.org/DmytroMitin/2FIP9ul1SeGp02MjHOizPA/2 – Dmytro Mitin Oct 06 '22 at 22:52
2

You can always use scalac to compile a scala class and then load that class dynamically. But I guess that's not what you're after.

Kim Stebel
  • 41,826
  • 12
  • 125
  • 142
  • Well, that would work. The "interpreter" invokes the compiler internally anyway. But it seems that the compiler is not any more straightforward to embed than the interpreter is. – Thilo Jul 28 '09 at 13:34
  • 1
    Depends on how you want to "embed" it. The easiest way is to call it as an external program. But if you want better integration of your program with the compiler, you can find a discussion of how to do that here: http://www.nabble.com/Compiler-API-td12050645.html – Kim Stebel Jul 28 '09 at 15:59
  • The link in @KimStebel's comment is dead but its archived version can be seen at https://web.archive.org/web/20090523111913/www.nabble.com/Compiler-API-td12050645.html – Dmytro Mitin Sep 14 '22 at 21:45