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

From Expertiza_Wiki
Jump to navigation Jump to search
 
(52 intermediate revisions by 2 users not shown)
Line 1: Line 1:
= Introduction =
= Introduction =
* A
Through the use of the [http://en.wikipedia.org/wiki/Eval eval()] function in Ruby you can dynamically interpret code at run-time.  This capability gives the programmer the power to design applications that can rewrite themselves by generating new code and executing it.


= Pros and cons =
== Reasons eval() Can Be Useful ==
As with any feature there is a price to pay for the benefits.
This feature could be useful in dynamically adapting a program to different versions of interfaces, in generating tables or arrays of functions to be called in a state machine, or in creating a new class from existing classes.  Other reasons to use eval include allowing a user to submit arbitrary command sequences for evaluation, saving the developer from creating a complex expression parser (for more information see [http://www.beanshell.org/manual/embeddedmode.html#Macros Macros and Evaluation]).


== Pros ==
== eval() Support in Ruby and Java ==
* Dynamic Metaprogramming Capability
eval() capability is fully supported at the language level in Ruby, thus it is available without adding to or extending Ruby in any way.
* Flexibilility
* Ease of Use


== Cons ==
The base Java language does have the capability, with libraries such as [https://eval.dev.java.net/ Simple Expression Evaluator for Java], and [http://www.japisoft.com/formula/ JFormula 3.6 - Math expressions API], to evaluate mathematical expressions, but not arbitrary code.  This means that even with these libraries in Java, a programmer can evaluate some math at run time, but can't define new methods and then call them.  Because these features do not permit the evaluation of arbitrary code, it can not define new classes and methods, making it less powerful than Ruby's eval().
* Performance
* Security


= Ruby Example =
Although Java doesn't have a built in eval() type of function, the [http://beanshell.org/ BeanShell] addon is available which provides full eval() functionality, equivalent to Ruby's eval().
 
It is more common to see eval() type functions in interpreted languages then compiled languages. In compiled languages you will need some sort of mechanism for interpreting code at run-time which usually isn't built in.
 
= Advantages and Disadvantages of Using Eval()=
As with many powerful features, the ability of programs to use eval() to dynamically extend themselves at run time, by programatically generating and executing new code, comes with benefits and potential disadvantages.  These advantages and disadavantages are similar for Java and Ruby, and apply to any language which offers this dynamic eval() capability.
 
== Advantages ==
eval() provides some powerful advantages to the programmer, including the ability to write programs that can compose (and execute) arbitrary new code at run time.
 
=== Dynamic Metaprogramming Capability ===
The capability to generate new code at run time provides the application developer the option of having the program dyamically extend itself, leading to a dynamic [http://en.wikipedia.org/wiki/Metaprogramming Metaprogramming] capability.
 
=== Flexibilility ===
Ruby's eval() capability permits Ruby developers to create flexible applications able to rewrite and extend themselves on the fly.  Even a statically typed, compiled language such as Java can take advantage of this flexibility through the BeanShell addon.
 
=== Ease of Use ===
eval() makes it easy to extend the functionality of programs at run time, to adapt to new requirements or changes in the underlying data model.  Because the interpreter or virtual machine instance retains state across invocations during the instance lifetime, the current process, and all new code passed to eval(), are available to the application, easing the burden on the programmer.
 
== Disadvantages ==
The power and flexibility comes with the price of some performance and security.
 
=== Performance ===
eval() must parse the code and compile it at run time, and in view of this, the performance implications of interpreted languages apply.  The speed penalty may not be worth the flexibility of generating new code at run time in some cases.  In addition, adding new code will increase the memory required by the application, and the increased load on the processor may have to be considered for non-trivial run time evaluation.
 
=== Security ===
If eval() is used to generate and invoke code created with arbitrary data received from another, less trusted application, extreme care should be used.  Allowing an untrusted application to modify a running program is an enormous security risk.  It is difficult to imagine circumstances in which eval() should be used in safety critical applications.
 
= Ruby Example of Eval()=
The eval function can be used for dynamically calling functions. For example in Ruby:
The eval function can be used for dynamically calling functions. For example in Ruby:
   
   
Line 33: Line 57:
   end  
   end  
   
   
   # Factory Pattern
   # Function that will dynamically call other methods
   def CallFunction(functionname)
   def CallFunction(functionname)
       eval functionname
       eval functionname
Line 39: Line 63:
   
   
   #Results
   #Results
   irb(main):039:0> CallFunction functions[0]
   irb(main):039:0> CallFunction functions[0] # Call Function1
   inside function1
   inside function1
   => nil
   => nil
   irb(main):040:0> CallFunction functions[1]
   irb(main):040:0> CallFunction functions[1] # Call Function2
   inside function2
   inside function2
   => nil
   => nil
   irb(main):041:0> CallFunction functions[2]
   irb(main):041:0> CallFunction functions[2] # Call Function3
   inside function3
   inside function3
   => nil
   => nil


What makes this so powerful is that the function names in the array can be stored in an array or someplace else like a database or xml file.
The method names can be stored in an array and called dynamically at run-time. Taking this one step further we can store the function definition in an array as well:
Taking this one step further we can store the function definition in an array as well:
   
   
   #Create an array for the function name and function definition
   #Create an array for the function name and function definition
Line 68: Line 90:


= Java Example =
= Java Example =
The base Java language does not have a direct equivalent to Ruby's eval() facility, because Java is a compiled, statically typed language.  However, Java environments can use a facility similar to Ruby's eval() through the BeanShell addon, available from http://beanshell.org/bsh-2.0b4.jar. Because a Java program can create instances of the BeanShell interpreter, and submit arbitrary Java code to the interpreter for evaluation at run time, Java developers can take advantage of BeanShell's eval facility to create programs that create and execute new programs on the fly. BeanShell retains state across invocations, so that previously evaluated methods and variables are available to methods and variables that are evaluated later in the lifetime of each BeanShell instance.
The base Java language does not have a direct equivalent to Ruby's eval() facility, because Java is a compiled, statically typed language.  However, Java environments can use a facility similar to Ruby's eval() through the [http://beanshell.org/ BeanShell] addon, available from [http://beanshell.org/bsh-2.0b4.jar bsh-2.0b4].
 
Because a Java program can create instances of the BeanShell interpreter, and submit arbitrary Java code to the interpreter for evaluation at run time, Java developers can take advantage of BeanShell's eval facility to create programs that create and execute new programs on the fly.
 
A BeanShell interpreter object retains state across invocations, so that previously evaluated classes, objects, methods, and variables are available to classes, objects, methods, and variables that are evaluated later in the lifetime of each BeanShell instance. For details, see the [http://www.beanshell.org/manual/embeddedmode.html#eval() BeanShell Manual, Embedded Mode]


BeanShell is distributed as an executable jar, which when run, provides a BeanShell workspace in which Java code can be developed in a command line environment.  To view the output from the code below in the BeanShell Workspace, the user must invoke "File->Capture System in/out/err" from the "Bsh Workspace" menu, before running the code.
BeanShell is distributed as an executable jar, which when run, provides a BeanShell workspace in which Java code can be developed in a command line environment.  To view the output from the code below in the BeanShell Workspace, the user must invoke "File->Capture System in/out/err" from the "Bsh Workspace" menu, before running the code.
Line 104: Line 130:


   // Create an array for the function name and function definition
   // Create an array for the function name and function definition
   StringBuffer[] function1 = new StringBuffer[10];
   StringBuffer[] function1 = new StringBuffer[10]; // We could have more than one
   StringBuffer[] function2 = new StringBuffer[10];
   StringBuffer[] function2 = new StringBuffer[10]; // We could have more than one
   
   
   // Dynamically create/define function
   // Dynamically create/define function
Line 121: Line 147:


= Links =
= Links =
== Ruby Links ==
[http://www.ruby-doc.org/core-1.9/classes/Binding.src/M000335.html Ruby eval() binding]


[http://en.wikipedia.org/wiki/Eval Wikipedia::Eval]
[http://en.wikipedia.org/wiki/Eval#Ruby Ruby Eval() from Wikipedia]


[http://www.ruby-doc.org/core-1.9/classes/Binding.src/M000335.html link title]
== Java Links ==


[http://weblog.jamisbuck.org/2006/9/22/inspecting-a-live-ruby-process Inspecting a Live Ruby Process]
=== Alternative Java Expression Evaluators ===
[http://3d2f.com/tags/expression/evaluator/java/ Janini Java Expression Evaluator]


[http://onestepback.org/index.cgi/Tech/Ruby/RubyBindings.rdoc/style/print link title]
[http://sourceforge.net/projects/jeplite/ JEPLite: java expression parser enlited]


[http://forum.java.sun.com/thread.jspa?threadID=5120080&messageID=9417282 link title]
[http://www.jdocs.com/beanshell/2.0.b4/api-index.html?m=class&p=bsh&c=Interpreter&render=classic BeanShell Interpreter Class]


[http://3d2f.com/tags/expression/evaluator/java/ Java Expression Evaluator]
=== Message Board Threads on eval() in Java ===
[http://forum.java.sun.com/thread.jspa?threadID=5120080&messageID=9417282 Java Programming - evaluate expression]


[https://eval.dev.java.net/ link title]
[http://forum.java.sun.com/thread.jspa?threadID=5132451&messageID=9524869 eval() in Java?]


[http://www.japisoft.com/formula/ link title]
=== eval() in Javascript ===
[http://forum.java.sun.com/thread.jspa?threadID=474563&tstart=75 Is there an equivalent to eval() in javascript?]


[http://sourceforge.net/projects/jeplite/ link title]
[http://www.ibm.com/developerworks/java/library/j-javascripting1/ Invoke dynamic languages dynamically, Part 1: Introducing the Java scripting API]


[http://beanshell.org BeanShell]
=== Using BeanShell ===


[http://www.beanshell.org/manual/bshmanual.html#Calling_BeanShell_From_Java Calling BeanShell from Java]
[http://www.beanshell.org/manual/bshmanual.html#Calling_BeanShell_From_Java Calling BeanShell from Java]


[http://www.jdocs.com/beanshell/2.0.b4/api-index.html?m=class&p=bsh&c=Interpreter&render=classic link name]
[http://www.beanshell.org/manual/embeddedmode.html#eval() Embedding BeanShell in Your Application]
 
[http://www.google.com/search?hl=en&q=ExpressionEvaluator.parseExpression+dynamic link name]
 
[http://forum.java.sun.com/thread.jspa?threadID=474563&tstart=75 link name]
 
[http://forum.java.sun.com/thread.jspa?threadID=5132451&messageID=9524869 link name]
 
[http://www.ibm.com/developerworks/java/library/j-javascripting1/ link name]
 
[http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/jsp/el/Expression.html link name]
 
[http://www.developintelligence.com/javadoc/javax/servlet/jsp/el/ExpressionEvaluator.html#evaluate(java.lang.String,%20java.lang.Class,%20javax.servlet.jsp.el.VariableResolver,%20javax.servlet.jsp.el.FunctionMapper) link name]
 
[http://www.beanshell.org/manual/embeddedmode.html#eval() link name]
 
[http://www.beanshell.org/manual/embeddedmode.html link name]

Latest revision as of 00:10, 12 June 2008

Introduction

Through the use of the eval() function in Ruby you can dynamically interpret code at run-time. This capability gives the programmer the power to design applications that can rewrite themselves by generating new code and executing it.

Reasons eval() Can Be Useful

This feature could be useful in dynamically adapting a program to different versions of interfaces, in generating tables or arrays of functions to be called in a state machine, or in creating a new class from existing classes. Other reasons to use eval include allowing a user to submit arbitrary command sequences for evaluation, saving the developer from creating a complex expression parser (for more information see Macros and Evaluation).

eval() Support in Ruby and Java

eval() capability is fully supported at the language level in Ruby, thus it is available without adding to or extending Ruby in any way.

The base Java language does have the capability, with libraries such as Simple Expression Evaluator for Java, and JFormula 3.6 - Math expressions API, to evaluate mathematical expressions, but not arbitrary code. This means that even with these libraries in Java, a programmer can evaluate some math at run time, but can't define new methods and then call them. Because these features do not permit the evaluation of arbitrary code, it can not define new classes and methods, making it less powerful than Ruby's eval().

Although Java doesn't have a built in eval() type of function, the BeanShell addon is available which provides full eval() functionality, equivalent to Ruby's eval().

It is more common to see eval() type functions in interpreted languages then compiled languages. In compiled languages you will need some sort of mechanism for interpreting code at run-time which usually isn't built in.

Advantages and Disadvantages of Using Eval()

As with many powerful features, the ability of programs to use eval() to dynamically extend themselves at run time, by programatically generating and executing new code, comes with benefits and potential disadvantages. These advantages and disadavantages are similar for Java and Ruby, and apply to any language which offers this dynamic eval() capability.

Advantages

eval() provides some powerful advantages to the programmer, including the ability to write programs that can compose (and execute) arbitrary new code at run time.

Dynamic Metaprogramming Capability

The capability to generate new code at run time provides the application developer the option of having the program dyamically extend itself, leading to a dynamic Metaprogramming capability.

Flexibilility

Ruby's eval() capability permits Ruby developers to create flexible applications able to rewrite and extend themselves on the fly. Even a statically typed, compiled language such as Java can take advantage of this flexibility through the BeanShell addon.

Ease of Use

eval() makes it easy to extend the functionality of programs at run time, to adapt to new requirements or changes in the underlying data model. Because the interpreter or virtual machine instance retains state across invocations during the instance lifetime, the current process, and all new code passed to eval(), are available to the application, easing the burden on the programmer.

Disadvantages

The power and flexibility comes with the price of some performance and security.

Performance

eval() must parse the code and compile it at run time, and in view of this, the performance implications of interpreted languages apply. The speed penalty may not be worth the flexibility of generating new code at run time in some cases. In addition, adding new code will increase the memory required by the application, and the increased load on the processor may have to be considered for non-trivial run time evaluation.

Security

If eval() is used to generate and invoke code created with arbitrary data received from another, less trusted application, extreme care should be used. Allowing an untrusted application to modify a running program is an enormous security risk. It is difficult to imagine circumstances in which eval() should be used in safety critical applications.

Ruby Example of Eval()

The eval function can be used for dynamically calling functions. For example in Ruby:

  # Create an array of functions
  functions = ['function1','function2','function3']
  
  # Define functions
  def function1()
      puts "inside function1"
  end 

  def function2()
     puts "inside function2"
  end 

  def function3()
     puts "inside function3"
  end 

  # Function that will dynamically call other methods
  def CallFunction(functionname)
     eval functionname
  end 

  #Results
  irb(main):039:0> CallFunction functions[0] # Call Function1
  inside function1
  => nil
  irb(main):040:0> CallFunction functions[1] # Call Function2
  inside function2
  => nil
  irb(main):041:0> CallFunction functions[2] # Call Function3
  inside function3
  => nil

The method names can be stored in an array and called dynamically at run-time. Taking this one step further we can store the function definition in an array as well:

  #Create an array for the function name and function definition
  function1 = ['function4'] # We could have more then one
  function2 =['def function4 ()  puts "inside function4" end'] # We could have more then one
  
  # Dynamically create/define function
  eval function2[0]
  
  # Dynamically call the the name of the function
  irb(main):060:0> eval function1[0]
  inside function4
  => nil

So, in this example function4() is created dynamically at run-time. This allows us to store parts of the code as data and to create functions when needed. An application written using eval to dynamically generate functions would allow new functions to be added easily. For example, you could create new definitions of functions and insert them into a database table.

Java Example

The base Java language does not have a direct equivalent to Ruby's eval() facility, because Java is a compiled, statically typed language. However, Java environments can use a facility similar to Ruby's eval() through the BeanShell addon, available from bsh-2.0b4.

Because a Java program can create instances of the BeanShell interpreter, and submit arbitrary Java code to the interpreter for evaluation at run time, Java developers can take advantage of BeanShell's eval facility to create programs that create and execute new programs on the fly.

A BeanShell interpreter object retains state across invocations, so that previously evaluated classes, objects, methods, and variables are available to classes, objects, methods, and variables that are evaluated later in the lifetime of each BeanShell instance. For details, see the BeanShell Manual, Embedded Mode

BeanShell is distributed as an executable jar, which when run, provides a BeanShell workspace in which Java code can be developed in a command line environment. To view the output from the code below in the BeanShell Workspace, the user must invoke "File->Capture System in/out/err" from the "Bsh Workspace" menu, before running the code.

  import java.lang.StringBuffer;  // needed for mutable strings

  // Create an array for function names
  StringBuffer[] functions = new StringBuffer[4];

  // Define functions
  void function1() {System.out.println("inside function1");}
  void function2() {System.out.println("inside function2");}
  void function3() {System.out.println("inside function3");}

  // Factory Pattern
  void CallFunction (functionname) {eval(functionname + "();");}

  // Initialize function names
  functions[0] = new StringBuffer("function1");
  functions[1] = new StringBuffer("function2");
  functions[2] = new StringBuffer("function3");

  // Results
  bsh % CallFunction (functions[0]);
  inside function1
  bsh % CallFunction (functions[1]);
  inside function2
  bsh % CallFunction (functions[2]);
  inside function3
  bsh % 

As in the Ruby example, the function names in the array can be stored in an array, or someplace else like a database or xml file.

In addition, similar to the Ruby example, we can store the function definition in an array as well:

  // Create an array for the function name and function definition
  StringBuffer[] function1 = new StringBuffer[10]; // We could have more than one
  StringBuffer[] function2 = new StringBuffer[10]; // We could have more than one

  // Dynamically create/define function
  function1[0] = new StringBuffer("function4");

  // Dynamically call the the name of the function
  bsh % function2[0] = new StringBuffer("void function4() {System.out.println(\"inside 
  function 4\");}");
  bsh % eval(function2[0].toString());
  bsh % CallFunction (function1[0]);
  inside function 4
  bsh %

As in the Ruby example, in this Java example using BeanShell eval(), function4() is created dynamically at run-time. This allows us to store parts of the code as data and to create functions when needed. An application written using eval to dynamically generate functions would allow new functions to be added easily. For example, you could create new definitions of functions and insert them into a database table.

Links

Ruby Links

Ruby eval() binding

Ruby Eval() from Wikipedia

Java Links

Alternative Java Expression Evaluators

Janini Java Expression Evaluator

JEPLite: java expression parser enlited

BeanShell Interpreter Class

Message Board Threads on eval() in Java

Java Programming - evaluate expression

eval() in Java?

eval() in Javascript

Is there an equivalent to eval() in javascript?

Invoke dynamic languages dynamically, Part 1: Introducing the Java scripting API

Using BeanShell

Calling BeanShell from Java

Embedding BeanShell in Your Application