CSC/ECE 517 Summer 2008/wiki1 3 ref

From Expertiza_Wiki
Revision as of 03:15, 12 June 2008 by Hkdavis (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

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.

External links