CSC/ECE 517 Summer 2008/wiki1 7 n1: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 1: Line 1:
''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.''
''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.''


==Evaluation Options in Ruby==
==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.  This facility gives developers the ability to modify the runtime behavior of application.  
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.
Using eval method is straightforward in Ruby. For example:
 
===Kernel.eval===


  eval("puts \"Hello World\"") #--> Hello World
  eval("puts \"Hello World\"") #--> Hello World


===Kernel.eval with binding===
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:
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
  def get_binding
Line 23: Line 20:


===Object.instance_eval===
===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
  class Paginator
   def initialize
   def initialize
Line 36: Line 35:


===Module.class_eval===
===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.new
  klass.class_eval("def hello() puts \"Hello World\" end")
  klass.class_eval("def hello() puts \"Hello World\" end")
Line 41: Line 44:


==Benefits of Runtime Evaluation==
==Benefits of Runtime Evaluation==
There are many scenarios where the eval method can be utilized.
The evaluation facility is good for Metaprogramming, allowing 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.  For real-world example, the facility can be used to develop Shell Command application similar to irb (Interactive Ruby). 
 
Calling methods dynamically:
 
 
Evaluating input from user:
 
Add method to a class at run time


==Evaluation Options in Java==
==Evaluation Options in Java==
Java does not have eval method in its standard library due its nature of being static typing and a compiled language, not an interpreted language like Ruby.  However it is entirely possible to build an interpreter in Java that would provide similar facility.  Below are just few some approaches:
Java does not have eval method in its standard library due its nature of being static typing and a compiled language, not an interpreted language like Ruby.  However it is entirely possible to build an interpreter in Java that would provide similar facility.  Below are just a few approaches:
#For simple application, the use of Hashtable with String lookup key would be enough to execute some prewritten piece of code.  This is hardly runtime evaluation.
#For simplest application, you can use Hashtable with String lookup key to execute some prewritten piece of code.  This is hardly runtime evaluation, but provides a nice illusion.
#Java Reflection API providers developers the ability to examine or modify the runtime behavior of applications.  Developers can dynamically load Classes, examine private members, and invoke methods.  However it cannot be used to parse and evaluate any arbitrary string of Java code.  One workaround is to generate code on the fly and write it out to disc, use sun.tools.javac.Main to invoke javac.exe and compile the file into class file, finally using Class.forName of Reflection API to invoke the new code.
#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.  A parser generator is a tool that reads a grammar specification and converts it to a Java program that can recognize matches to the grammar. In addition to the parser generator itself, JavaCC provides other standard capabilities related to parser generation such as tree building (via a tool called JJTree included with JavaCC), actions, debugging, etc.
#Write a parser using JavaCC.  A parser generator is a tool that reads a grammar specification and converts it to a Java program that can recognize matches to the grammar. In addition to the parser generator itself, JavaCC provides other standard capabilities related to parser generation such as tree building (via a tool called JJTree included with JavaCC), actions, debugging, etc.
#Using third party scripting framework that runs in JVM, such as BeanShell, and Jpython.
#Using third party scripting framework that runs in JVM, such as BeanShell, and Jpython.

Revision as of 00:07, 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, allowing 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. For real-world example, the facility can be used to develop Shell Command application similar to irb (Interactive Ruby).

Evaluation Options in Java

Java does not have eval method in its standard library due its nature of being static typing and a compiled language, not an interpreted language like Ruby. However it is entirely possible to build an interpreter in Java that would provide similar facility. Below are just a few approaches:

  1. For simplest application, you can use Hashtable with String lookup key to execute some prewritten piece of code. This is hardly runtime evaluation, but provides a nice illusion.
  2. 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.
  3. Write a parser using JavaCC. A parser generator is a tool that reads a grammar specification and converts it to a Java program that can recognize matches to the grammar. In addition to the parser generator itself, JavaCC provides other standard capabilities related to parser generation such as tree building (via a tool called JJTree included with JavaCC), actions, debugging, etc.
  4. Using third party scripting framework that runs in JVM, such as BeanShell, and Jpython.
  5. Using Java 1.6 Scripting framework. It allows Java applications to host script engines. Third party script engines are supported by dropping any JSR-223 compliant script engine jar in the CLASSPATH and access the same from your Java applications. This mechanism is similar to the way JDBC drivers, JNDI implementations are accessed.
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

Getting the benefit of runtime evaluation in Java is certainly not impossible, but it isn't easy. Generally Java developers need to determine which of the evaluation options above best suits the application. Using third party scripting engine, the developers need to determine if third-party libraries are compatible with the Java version the project will be using. They need to learn the third party library's API, and syntax for scripting engine. The learning curve is much more steeper for those choose to writer a parser using JavaCC. In addition to learning JavaCC syntax, developers must have knowledge in compiler design and have thorough understanding of Java language and grammar. Java 1.6 introduces Scripting for Java Platform, a powerful scripting framework, but this does not eliminate the fact developers must learn another scripting language to use the framework. Consider Java 1.6 scripting framework the simplest solution, a simple printing "Hello World" application requires 8 lines of code as opposite to 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.