CSC/ECE 517 Summer 2008/wiki1 3 ref: Difference between revisions
No edit summary |
No edit summary |
||
(3 intermediate revisions by the same user not shown) | |||
Line 3: | Line 3: | ||
== What is Reflection? == | == What is Reflection? == | ||
Reflection is the a programming paradigm that allows a program to examine it's own code, and modify itself or execute code generated dynamically. | [http://en.wikipedia.org/wiki/Reflection_%28computer_science%29 Reflection] is the a programming paradigm that allows a program to examine it's own code, and modify itself or execute code generated dynamically. Wikipedia's description of Reflection says "Reflection is the process by which a computer program can observe and modify its own structure and behavior." It provides a way for a program to change it's behavior and state based on it's current behavior and state. | ||
In the paper [[http://www.cs.indiana.edu/~jsobel/rop.html An Introduction to Reflection-Oriented Programming]], it is explained with a real-world analogy: | In the paper [[http://www.cs.indiana.edu/~jsobel/rop.html An Introduction to Reflection-Oriented Programming]], it is explained with a real-world analogy: | ||
Line 10: | Line 10: | ||
== Ruby Reflection == | == Ruby Reflection == | ||
In Ruby, metaprogramming is an important feature. Because it is also a dynamically typed language, it's very useful to be able to examine the type of a given object at runtime, since it's type is not always known at compile time. Thus, a mechanism to change the program's behavior at runtime is needed. This is the reasoning behind Ruby's strong support of reflection. Ruby allows a program to examine the properties of any given object to determine it's supported methods, members, etc. It also provides mechanisms to examine the class structure of a method, including it's class heirarchy and meta information such as access modifiers. | In Ruby, [http://en.wikipedia.org/wiki/Metaprogramming metaprogramming] is an important feature. Because it is also a dynamically typed language, it's very useful to be able to examine the type of a given object at runtime, since it's type is not always known at compile time. Thus, a mechanism to change the program's behavior at runtime is needed. This is the reasoning behind Ruby's strong support of reflection. Ruby allows a program to examine the properties of any given object to determine it's supported methods, members, etc. It also provides mechanisms to examine the class structure of a method, including it's class heirarchy and meta information such as access modifiers. | ||
Since objects in Ruby are dynamically typed, any method can be called on any object. Because the compiler doesn't impose restrictions on types, the runtime doesn't either, so Ruby code is able to call methods on objects dynamically at runtime. | Since objects in Ruby are dynamically typed, any method can be called on any object. Because the compiler doesn't impose restrictions on types, the runtime doesn't either, so Ruby code is able to call methods on objects dynamically at runtime. | ||
== Java Reflection API == | == Java Reflection API == | ||
In Java, reflection capabilities are available, but they are not built into the language. The java.lang.reflect package provides the API for reflection, along with the another important class, java.lang.Class. | In Java, reflection capabilities are available, but they are not built into the language. The java.lang.reflect package provides the API for reflection, along with the another important class, java.lang.Class. Metaprogramming is writing code that writes and executes other code at runtime, and reflection is one way to implement that. Since metaprogramming is not a feature or Java, reflection in Java typically requires more code than Ruby does, and thus is not as easy to use. It also has several drawbacks, such as security restrictions and performance overhead [[http://java.sun.com/docs/books/tutorial/reflect/index.html Sun Java Reflection tutorial]]. It is also more limited than Ruby's reflection capabilities, as demonstrated below. | ||
== Java Limitations == | == Java Limitations == | ||
Line 26: | Line 26: | ||
This prints out the value of each Numeric type object that exists in the Ruby environment. Java's reflection API doesn't provide a mechanism to iterate over Objects that you don't already have a reference to. While this functionality could be provided by an extension to the JVM or a third party library, in Ruby, it is built into the language from the ground up. | This prints out the value of each Numeric type object that exists in the Ruby environment. Java's reflection API doesn't provide a mechanism to iterate over Objects that you don't already have a reference to. While this functionality could be provided by an extension to the JVM or a third party library, in Ruby, it is built into the language from the ground up. | ||
== Ruby | == Ruby vs. Java Examples == | ||
Here are some examples of Java and Ruby code that demonstrate how each language accomplishes the same task using it's reflection capabilities. | Here are some original examples of Java and Ruby code that demonstrate how each language accomplishes the same task using it's reflection capabilities. | ||
=== List methods of | === List Methods of a Class === | ||
What follows are the implementations of listing all the methods of an array class in both languages. As you can see, the Ruby example is much simpler, since reflection is built into the array class itself. | |||
==== Java ==== | |||
In java, to print the names of all the methods an Object[] has, the following code is needed: | In java, to print the names of all the methods an Object[] has, the following code is needed: | ||
Object[] objArray = new Object[]{"Hello World"}; | Object[] objArray = new Object[]{"Hello World"}; | ||
Line 37: | Line 40: | ||
} | } | ||
=== | ==== Ruby ==== | ||
In Ruby, the same functionality is a single line: | In Ruby, the same functionality is a single line: | ||
puts Array.methods | puts Array.methods | ||
=== Invoke | === Invoke a Method on an Instance === | ||
In this section I demonstrate how to make a simple method call in each language using reflection. | |||
==== Java ==== | |||
In Java, the indexOf(String) method is used to find the index of a substring in a given String | In Java, the indexOf(String) method is used to find the index of a substring in a given String | ||
"Hello World".indexOf("W"); | "Hello World".indexOf("W"); | ||
To use reflection to make | To use reflection to make that method call requires the following code: | ||
String s = "Hello World"; | String s = "Hello World"; | ||
Method method; | Method method; | ||
Line 64: | Line 70: | ||
As you can see, this requires creating arrays of Class objects to specify parameter types, and possibly casting the result of the method call from Object to the correct type. It also requires you to catch 3 possible Exceptions that may occur. Ruby's reflections mechanisms don't require exception handling. | As you can see, this requires creating arrays of Class objects to specify parameter types, and possibly casting the result of the method call from Object to the correct type. It also requires you to catch 3 possible Exceptions that may occur. Ruby's reflections mechanisms don't require exception handling. | ||
=== | ==== Ruby ==== | ||
In Ruby, the same method call is: | In Ruby, the same method call is: | ||
"Hello World".index("W") | "Hello World".index("W") | ||
Line 73: | Line 79: | ||
method.call("W") | method.call("W") | ||
==External links== | == Conclusions == | ||
As you can see from the examples, both languages are capable of much of the same functionality. The major advantage for Ruby's reflection is it's holistic inclusion into the language, instead of an addition as a library. It requires less code and has simpler syntax, and thus takes less work to write and maintain. It increases code flexibility by encouraging programmers to dive right into it's features, instead of having to learn another library and overcome security and performance problems as in Java. | |||
== External links == | |||
*[http://java.sun.com/docs/books/tutorial/reflect/index.html Java Reflection Tutorial] | *[http://java.sun.com/docs/books/tutorial/reflect/index.html Java Reflection Tutorial] | ||
*[http://java.sun.com/javase/6/docs/api/java/lang/reflect/package-summary.html java.lang.reflect Package API] | *[http://java.sun.com/javase/6/docs/api/java/lang/reflect/package-summary.html java.lang.reflect Package API] | ||
*[http://java.sun.com/javase/6/docs/api/java/lang/Class.html java.lang.Class API] | *[http://java.sun.com/javase/6/docs/api/java/lang/Class.html java.lang.Class API] | ||
*[http://phrogz.net/programmingruby/ospace.html Reflection, ObjectSpace, and Distributed Ruby] | *[http://phrogz.net/programmingruby/ospace.html Reflection, ObjectSpace, and Distributed Ruby] |
Latest revision as of 03:15, 12 June 2008
Introduction
Reflection is built into Ruby, but in Java, it's a special API. Does this make Ruby code easier to write than Java code? Give examples of reflection sequences in both languages, and analyze which is clearer, and also, if possible, which is more efficient.
What is Reflection?
Reflection is the a programming paradigm that allows a program to examine it's own code, and modify itself or execute code generated dynamically. Wikipedia's description of Reflection says "Reflection is the process by which a computer program can observe and modify its own structure and behavior." It provides a way for a program to change it's behavior and state based on it's current behavior and state.
In the paper [An Introduction to Reflection-Oriented Programming], it is explained with a real-world analogy:
The concept of reflection is best understood by reaching back to the study of self-awareness in artificial intelligence: "Here I am walking down the street in the rain. Since I'm starting to get drenched, I should open my umbrella." This thought fragment reveals a self-awareness of behavior and state, one that leads to a change in that selfsame behavior and state. It would be desirable for computations to avail themselves of these reflective capabilities, examining themselves in order to make use of meta-level information in decisions about what to do next.
Ruby Reflection
In Ruby, metaprogramming is an important feature. Because it is also a dynamically typed language, it's very useful to be able to examine the type of a given object at runtime, since it's type is not always known at compile time. Thus, a mechanism to change the program's behavior at runtime is needed. This is the reasoning behind Ruby's strong support of reflection. Ruby allows a program to examine the properties of any given object to determine it's supported methods, members, etc. It also provides mechanisms to examine the class structure of a method, including it's class heirarchy and meta information such as access modifiers.
Since objects in Ruby are dynamically typed, any method can be called on any object. Because the compiler doesn't impose restrictions on types, the runtime doesn't either, so Ruby code is able to call methods on objects dynamically at runtime.
Java Reflection API
In Java, reflection capabilities are available, but they are not built into the language. The java.lang.reflect package provides the API for reflection, along with the another important class, java.lang.Class. Metaprogramming is writing code that writes and executes other code at runtime, and reflection is one way to implement that. Since metaprogramming is not a feature or Java, reflection in Java typically requires more code than Ruby does, and thus is not as easy to use. It also has several drawbacks, such as security restrictions and performance overhead [Sun Java Reflection tutorial]. It is also more limited than Ruby's reflection capabilities, as demonstrated below.
Java Limitations
Something Ruby can do that Java can't is to iterate over the collection all of the objects of a certain type or simply all objects that exist in the runtime. The ObjectSpace class in Ruby has a method each_object(), which iterates over each object that matches the type of it's parameter. This example from [Programming Ruby: The Pragmatic Programmer's Guide] illustrates it's use.
a = 102.7 b = 95.1 ObjectSpace.each_object(Numeric) {|x| p x }
This prints out the value of each Numeric type object that exists in the Ruby environment. Java's reflection API doesn't provide a mechanism to iterate over Objects that you don't already have a reference to. While this functionality could be provided by an extension to the JVM or a third party library, in Ruby, it is built into the language from the ground up.
Ruby vs. Java Examples
Here are some original examples of Java and Ruby code that demonstrate how each language accomplishes the same task using it's reflection capabilities.
List Methods of a Class
What follows are the implementations of listing all the methods of an array class in both languages. As you can see, the Ruby example is much simpler, since reflection is built into the array class itself.
Java
In java, to print the names of all the methods an Object[] has, the following code is needed:
Object[] objArray = new Object[]{"Hello World"}; Method[] methods = objArray.getClass().getMethods(); for (Method m : methods) { System.out.println(m.getName()); }
Ruby
In Ruby, the same functionality is a single line:
puts Array.methods
Invoke a Method on an Instance
In this section I demonstrate how to make a simple method call in each language using reflection.
Java
In Java, the indexOf(String) method is used to find the index of a substring in a given String
"Hello World".indexOf("W");
To use reflection to make that method call requires the following code:
String s = "Hello World"; Method method; try { method = s.getClass().getMethod("indexOf", new Class[]{String.class}); Object result = method.invoke(s, "W"); System.out.println(result); } catch(NoSuchMethodException nsme) { nsme.printStackTrace(); } catch(IllegalAccessException iae) { iae.printStackTrace(); } catch(InvocationTargetException ite) { ite.printStackTrace(); }
As you can see, this requires creating arrays of Class objects to specify parameter types, and possibly casting the result of the method call from Object to the correct type. It also requires you to catch 3 possible Exceptions that may occur. Ruby's reflections mechanisms don't require exception handling.
Ruby
In Ruby, the same method call is:
"Hello World".index("W")
Using reflection, this is reduced to a simple 3 lines of code
s = "Hello World" method = s.method("index") method.call("W")
Conclusions
As you can see from the examples, both languages are capable of much of the same functionality. The major advantage for Ruby's reflection is it's holistic inclusion into the language, instead of an addition as a library. It requires less code and has simpler syntax, and thus takes less work to write and maintain. It increases code flexibility by encouraging programmers to dive right into it's features, instead of having to learn another library and overcome security and performance problems as in Java.