"eval" in Scala
Asked Answered
C

6

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.

Caviness answered 26/7, 2009 at 3:23 Comment(1)
Scala 2 #73912301 Scala 3 #70945820Thin
V
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.

Venatic answered 26/7, 2009 at 20:20 Comment(8)
+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.Faucet
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.Caviness
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.Venatic
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: hackage.haskell.org/package/hintPurgative
@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.Crosspatch
@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).Inchmeal
"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.Valdis
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.Pileate
C
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

Corn answered 21/5, 2011 at 15:39 Comment(10)
That is not a "third-party" package, it's part of the Scala language implementation proper.Scorify
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.Eisenhart
@Kipton and nsc.interpreter.ISettings as well I think. Unfortunately I and others are getting values ClassCastExceptions: #6367893 (when I tried to test out my answer recently) and https://mcmap.net/q/66049/-scala-as-scripting-language-duplicate/…Corn
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: #4122067Eisenhart
As of 2.10, you can build source trees and compile them with scala.tools.reflect.ToolBox#eval. See slide 35 of scalamacros.org/talks/2012-04-28-MetaprogrammingInScala210.pdfBurmeister
404: Page Not FoundBatman
it's 2018 going on 2019.Pileate
importing scala.tools.nsc.Interpreter gives a deprecation warning. Link is dead. It is 2022.... sorry, have to downvote. Please fix this answer.Damson
@Damson feel free to let us know if interpreter is deprecatedCorn
Scala 3 dotty.tools.repl.ScriptEngine, Scala 2 scala.tools.nsc.interpreter.shell.ScriptedThin
V
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.

Venatic answered 26/7, 2009 at 20:20 Comment(8)
+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.Faucet
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.Caviness
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.Venatic
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: hackage.haskell.org/package/hintPurgative
@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.Crosspatch
@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).Inchmeal
"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.Valdis
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.Pileate
E
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.

Enjoyable answered 2/6, 2013 at 14:49 Comment(0)
C
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
Commissionaire answered 31/10, 2011 at 7:9 Comment(3)
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).Siamang
The last version is 6.43.0 (April 2017) github.com/twitter/util/blob/util-6.43.0/util-eval/src/main/… libraryDependencies += "com.twitter" % "util-eval_2.12" % "6.43.0"Thin
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") scastie.scala-lang.org/DmytroMitin/2FIP9ul1SeGp02MjHOizPA/2Thin
S
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

Steamship answered 29/6, 2015 at 14:13 Comment(2)
Doesn't work: "object tools is not a member of package scala"Biased
It's required to reference "org.scala-lang" % "scala-compiler" along to "scala-reflect", then the code above compiles and runs fine.Tweed
S
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.

Stjohn answered 28/7, 2009 at 9:58 Comment(3)
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.Caviness
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: nabble.com/Compiler-API-td12050645.htmlStjohn
The link in @KimStebel's comment is dead but its archived version can be seen at web.archive.org/web/20090523111913/www.nabble.com/…Thin

© 2022 - 2024 — McMap. All rights reserved.