CSC/ECE 517 Summer 2008/wiki1 3 ref

From Expertiza_Wiki
Revision as of 02:33, 12 June 2008 by Hkdavis (talk | contribs)
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. The definition of Reflection from the [Wikipedia Reflection article] 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."


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 is also more limited than Ruby's reflection capabilities, as demonstrated below.

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 Limitations

Something Ruby can do is to iterate over all of the objects of a certain type. The ObjectSpace class in Ruby has a method each_object(), which iterates over each object that matches the type of it's parameter.

       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.


Ruby v. 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.

List methods of a class - 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());
       }

List methods of a class - Ruby

In Ruby, the same functionality is a single line:

       puts Array.methods

Invoke method on an instance - 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 this 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.

Invoke method on an instance - 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")

External links