CSC/ECE 517 Summer 2008/wiki1 7 n1: Difference between revisions
Line 71: | Line 71: | ||
==Conclusion== | ==Conclusion== | ||
Java does not have the eval method in its standard library, but it is possible to develop a similar facility. That said, it is not easy. If using third party script engine, Java developers need to determine if third-party libraries are compatible with the Java version the project is currently using or will be using. And there is the risk of library dependency conflict. Once a script engine is chosen, Java developers also need to learn the API and likely new syntax used by the script engine. The learning curve is much more steeper for those choose to write a parser using JavaCC. In addition to learning JavaCC syntax, developers must have knowledge in compiler design concepts, such as top-down, parse-tree, etc. Developers must also have thorough understanding of Java language and grammar. Java 1.6 introduces Scripting for Java Platform, a powerful scripting framework, but it does not eliminate the fact developers must learn another language to use the framework. Consider Java 1.6 scripting framework the simplest solution, a simple program printing "Hello World" requires about 8 lines of code (see example from the previous section) as opposite to just 1 line of code in Ruby. Fortunately with Apache Bean Framework and JRuby to bridge Java and Ruby, developers won't have to choose or another. | Java does not have the eval method in its standard library, but it is possible to develop a similar facility. That said, it is not easy. If using third party script engine, Java developers need to determine if third-party libraries are compatible with the Java version the project is currently using or will be using. And there is the risk of library dependency conflict. Once a script engine is chosen, Java developers also need to learn the API and likely new syntax used by the script engine. The learning curve is much more steeper for those choose to write a parser using JavaCC. In addition to learning JavaCC syntax, developers must have knowledge in compiler design concepts, such as top-down, parse-tree, etc. Developers must also have thorough understanding of Java language and grammar. Java 1.6 introduces Scripting for Java Platform, a powerful scripting framework, but it does not eliminate the fact developers must learn another language to use the framework. Consider Java 1.6 scripting framework the simplest solution, a simple program printing "Hello World" requires about 8 lines of code (see example from the previous section) as opposite to just 1 line of code in Ruby. Fortunately with Apache Bean Framework and JRuby to bridge Java and Ruby, developers won't have to choose one or another. |
Revision as of 01:20, 7 June 2008
Ruby's eval can parse and execute an arbitrary string of Ruby code. Does Java have a similar facility? Provide an illustration of what this facility is good for. Compare the ease of writing such code in Ruby vs. writing equivalent code in Java.
Flavors of eval
The eval method is one of the most powerful features of Ruby. The Kernel.eval will parse and execute an arbitrary string of legal Ruby source code. To put it plainly, if your Ruby program can generate a string of valid Ruby code, the Kernel.eval method can evaluate that code. The eval method gives developers the ability to modify the runtime behavior of application.
Using eval method is straightforward in Ruby. For example:
eval("puts \"Hello World\"") #--> Hello World
This is overly simplistic example, but illustrate the concept well. You can optionally specify a binding with the eval method. If a binding is given, the evaluation will be performed in the context of the binding. For example:
def get_binding a = 1 binding end a = 2 the_binding = get_binding eval("puts a", the_binding) #--> 1 eval("puts a") #--> 2
Object.instance_eval
In addition to switching context with binding, the instance_eval method of Object allows you to evaluate a string or block in the context of an instance of a class. It allows you to create a block of code in any context and evaulate it later in the context of an individual instance.
class Paginator def initialize @page_index = 0 end def next @page_index += 1 end end paginator = Paginator.new paginator.next paginator.instance_eval("puts @page_index") #=> 1
Module.class_eval
Similarly, the class_eval or module_eval method of Module allows you to evaluate a string or block in the context of a class or module.
You can use class_eval to add methods to a class as well as include other modules in a class.
klass = Class.new klass.class_eval("def hello() puts \"Hello World\" end") klass.new.hello #==> Hello World
Benefits of Runtime Evaluation
The evaluation facility is good for Metaprogramming. It allows developers to write programs that are modifiable at run time, and have program write programs. The simple examples shown in the previous section already demonstrate several powerful concepts, such as calling methods dynamically, and add method to a class at run time. Here are couple of real-world applications of this facility:
- The ability for program to write programs combined generative programming concept could save developers tons of time.
- Development of Shell Command application similar to irb (Interactive Ruby).
- Mathematical Expression Evaluator
- Program that gives users the ability to write scripts and to enhance its functions. For example, scripting in game.
Evaluation Options in Java
Unlike Ruby, Java has static typing and is a compiled language, not an interpreted language. Java does not have eval method in its standard library. However it is entirely possible to write an interpreter in Java that would provide similar facility. Below are just a few approaches:
- For simplest application, you can use Hashtable with String lookup key to execute some prewritten piece of code. This is hardly considered runtime evaluation, but provides a nice illusion.
- Java Reflection API gives you the ability to examine or modify the runtime behavior of applications. Developers can dynamically load classes, examine private members reflectively, and invoke methods. However it cannot be used to parse and evaluate any arbitrary string of Java code. The workaround is to use generative programming; you program will generate code on the fly, compile the newly generated source code at runtime, reflectively invoke the compiled code. In Java 5, you can generate codes to a file on hard disk, use sun.tools.javac.Main to invoke javac.exe and compile the file into class file, finally using Class.forName of Reflection API to load the generated code into program.
- Write a parser using JavaCC. JavaCC is a parser generator that reads a grammar specification and converts it to a Java program that can recognize matches to the grammar. When combined with the concept of compile and load at runtime, this is a powerful solution that can evaluate not only a string of Java code.
- Using third party scripting engine that runs in JVM, such as BeanShell, Jpython, etc. Some of the engines utilize the concept from the previous bullet, generally translating well-known scripting language into Java bytecodes at runtime.
- Using Java 1.6 Scripting framework. It allows Java applications to host script engines. This approach is similar to the previous bullet, except the framework provides an easier approach to integrate script engines. Ideally third party script engine is supported by dropping any JSR-223 compliant script engine jar in the CLASSPATH and uniformly access it from your Java applications. This mechanism is similar to the way JDBC drivers, JNDI implementations are accessed. For example, loading a Script Engine (based on Rhino: JavaScript for Java version 1.6R2) included in Java SE 6:
import javax.script.*; public class EvalScript { public static void main(String[] args) throws Exception { // create a script engine manager ScriptEngineManager factory = new ScriptEngineManager(); // create a JavaScript engine ScriptEngine engine = factory.getEngineByName("JavaScript"); // evaluate JavaScript code from String engine.eval("print('Hello, World')"); } }
Conclusion
Java does not have the eval method in its standard library, but it is possible to develop a similar facility. That said, it is not easy. If using third party script engine, Java developers need to determine if third-party libraries are compatible with the Java version the project is currently using or will be using. And there is the risk of library dependency conflict. Once a script engine is chosen, Java developers also need to learn the API and likely new syntax used by the script engine. The learning curve is much more steeper for those choose to write a parser using JavaCC. In addition to learning JavaCC syntax, developers must have knowledge in compiler design concepts, such as top-down, parse-tree, etc. Developers must also have thorough understanding of Java language and grammar. Java 1.6 introduces Scripting for Java Platform, a powerful scripting framework, but it does not eliminate the fact developers must learn another language to use the framework. Consider Java 1.6 scripting framework the simplest solution, a simple program printing "Hello World" requires about 8 lines of code (see example from the previous section) as opposite to just 1 line of code in Ruby. Fortunately with Apache Bean Framework and JRuby to bridge Java and Ruby, developers won't have to choose one or another.