Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do people say that Java can't have an expression evaluator?

I am aware that by default Java does not have the so-called eval (what I pronounce as "evil") method. This sounds like a bad thing—knowing you do not have something which so many others do. But even worse seems being notified that you can't have it.

My question is: What is solid reasoning behind it? I mean, Google'ing this just returns a massive amount of old data and bogus reasons—even if there is an answer that I'm looking for, I can't filter it from people who are just throwing generic tag-words around.

I'm not interested in answers that are telling me how to get around that; I can do that myself:

Using Bean Scripting Framework (BSF)

File sample.py (in py folder) contents:

def factorial(n): 
    return reduce(lambda x, y:x * y, range(1, n + 1))

And Java code:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("jython");
engine.eval(new FileReader("py" + java.io.File.separator + "sample.py"));
System.out.println(engine.eval("factorial(932)"));

Using designed bridges like JLink

example

This is equivalent to:

String expr = "N[Integrate[E^(2 y^5)/(2 x^3), {x, 4, 7}, {y, 2, 3}]]";
System.out.println(MM.Eval(expr));
//Output: 1.5187560850359461*^206 + 4.2210685420287355*^190*I

Other methods

  • Using Dijkstras shunting-yard algorithm or alike and writing an expression evaluator from scratch.
  • Using complex regex and string manipulations with delegates and HashMultimaps.
  • Using Java Expressions Library
  • Using Java Expression Language
  • Using JRE compliant scripting language like BeanShell.
  • Using the Java Assembler and approach below or direct bytecode manipulation like Javaassist.
  • Using the Java Compiler API and reflections.
  • Using Runtime.getRuntime().exec as root
like image 650
Margus Avatar asked Mar 12 '11 20:03

Margus


People also ask

Does Java have eval?

No, you can not have a generic "eval" in Java (or any compiled language). Unless you're willing to write a Java compiler AND a JVM to be executed inside of your Java program.

Does Java evaluate expression left to right?

Java expressions are evaluated following the following rules: Operands are evaluated from left to right. The operands of an operator are evaluated before the operator. Operators are evaluated according to operator precedence.

What is Java expression parser?

JEP is a Java API for parsing and evaluating mathematical expressions. With this library you can allow your users to enter an arbitrary formula as a string, and instantly evaluate it. JEP supports user defined variables, constants, and functions. A number of common mathematical functions and constants are included.


2 Answers

"eval" is only available in scripting languages, because it uses the same interpreter that runs the rest of the code; in such languages the feature is free and well integrated, as in scripting environment it makes little difference if you run a string or a "real" function.

In copiled languages, adding "eval" would mean bundling the whole compiler - which would defy the purpose of compiling. No compiled language I know (even dynamic ones, like ActionScrip3) has eval.

Incidentally, the easiest way to eval in Java is the one you forgot to mention: JRE 1.6 comes with Javascript engine, so you can eval any Javascript in two lines of code. You could even argue that the presuposition of your question is false. Java 1.6 bundles a very advanced expression evaluator.

like image 166
fdreger Avatar answered Sep 27 '22 20:09

fdreger


As Daniel points out there is at least one limitation that eval-solutions face in java. The php eval for example executes the code as if it was part of the surrounding method with complete access to local variables, this is not possible to do in standard java. Without this feature eval alternatives require a lot more work and verbosity, which makes them a lot less attractive for "quick" and "easy" solutions.

eval() is mostly part of interpreted languages where the names of local variables and code structure(scopes) are available at runtime, making it possible to "insert" new code. Java bytecode no longer contains this information leaving eval() alternatives unable to map access to local variables. (Note: I ignore debug information as no program should rely on it and it may not be present)

An example

int i = 0;
eval("i = 1");
System.out.println(i);

required pseudocode for java

context.put("i",new Integer(0));
eval(context,"i = 1");
System.out.println(context.get("i"));

This looks nice for one variable used in the eval, try it for 10 in a longer method and you get 20 additional lines for variable access and the one or other runtime error if you forget one.

like image 30
josefx Avatar answered Sep 27 '22 21:09

josefx