CSC/ECE 517 Fall 2010/ch3 1c AE: Difference between revisions
(→Ruby) |
|||
(152 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
= Reflective Language Features vs. Reflective Packages = | |||
== Definition == | == Definition == | ||
Reflection is the ''integral'' quality of a program to dynamically manipulate its own state. More specifically, the program can infer and modify itself by making use of the representation of its own state. The state of a program can be its implementation aspects like syntax, semantics, structure, etc. The program acts through its self-accessible state and takes itself as its domain to be acted upon. Programming languages that possess this quality are said to be reflective. | Reflection is the ''integral'' quality of a program to dynamically manipulate its own state. More specifically, the program can infer and modify itself by making use of the representation of its own state. The state of a program can be its implementation[[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.158.2012&rep=rep1&type=pdf 5]] aspects like syntax, semantics, structure, etc. The program acts through its self-accessible state and takes itself as its domain to be acted upon. Programming languages that possess this quality are said to be reflective.[[http://www.cs.indiana.edu/~jsobel/rop.html 2]] | ||
Most object-oriented languages support some form of reflection. Smalltalk, Ruby, and Python in particular have very powerful and flexible reflection mechanisms. Java also supports reflection, but not | Most object-oriented languages support some form of reflection. Smalltalk, Ruby, and Python in particular have very powerful and flexible reflection mechanisms. Java[[http://www.ub.uni-konstanz.de/kops/volltexte/2002/803/pdf/DissertationEgbertAlthammer.pdf 6]] also supports reflection, but not as flexible and dynamic fashion as the others. C++ does not support reflection as we've defined it here, but it does support a limited form of run-time type information that allows a program to determine the type of an object at run-time. Eiffel also has support for a limited form of reflection, although it is much improved in the most recent versions of Eiffel, including the ability to determine the features contained in an object. | ||
Consider a simple example of Reflection in Java below : | Consider a simple example of Reflection in Java below : | ||
<h3> | |||
<pre> | |||
public class HelloWorld { | |||
public void printName() { | |||
System.out.println(this.getClass().getName()); | |||
} | |||
} | |||
</pre> | |||
</h3> | |||
The line | The line ''(obj.HelloWorld()).printName();'' sends the string 'HelloWorld' to the standard output. Let ''obj'' be an object of HelloWorld or one of its subclasses. When the program reaches the line, ''obj.printName();'' it sends the name of the class to the standard output. | ||
sends the string 'HelloWorld' to the standard output. Let ''obj'' be an object of HelloWorld or one of its subclasses. When the program reaches the line, | |||
it sends the name of the class to the standard output. | |||
This simple example denotes an effective feature. The printName method looks at the object ''obj'' for its class (this.getClass()). It decides what to print by delegating to the object's class in runtime.(i.e.,) the printName method behaves differently for each subclass of HelloWorld. The method is so flexible that it dynamically adapts itself to the class or subclass that inherits it. | This simple example denotes an effective feature. The printName method looks at the object ''obj'' for its class (this.getClass()). It decides what to print by delegating to the object's class in runtime.(i.e.,) the printName method behaves differently for each subclass of HelloWorld. The method is so flexible that it dynamically adapts itself to the class or subclass that inherits it. | ||
Reflection being an effective language feature enables [http:// | Reflection being an effective language feature enables [http://pg-server.csc.ncsu.edu/mediawiki/index.php/CSC/ECE_517_Fall_2010/ch4_4g_km metaprogramming][[http://www.laputan.org/reflection/ooffrmla.html 7]]. A reflective system would possess the feature of allowing programmers to design, create make use of the objects to act dynamically based on an existing part of the running system. Thus, reflection can also be defined as a feature where a programming language behaves like its own metalanguage. | ||
It contains [http://en.wikipedia.org/wiki/Metadata metadata] and associated operations to manipulate it in runtime. | It contains [http://en.wikipedia.org/wiki/Metadata metadata] and associated operations to manipulate it in runtime. | ||
== | Another important concept that is closely associated with reflection is reification. Reification is the process of packaging the information about the environment suitable so that it can be manipulated(by reflection). | ||
== Reflective mechanisms == | |||
Reflection is a feature that is made available in a language that facilitatates either reification or reflection or both. | |||
=== Categorizing Reflection === | |||
There two primary criteria to categorize reflective systems. These criteria are based on when reflection happens and what is reflected. Considering what is being reflected, the categories of reflective systems are : | |||
* '''Introspection''': This is the ability of the program to identify the type of an object and its methods. Here, the structure is identified and accessed but not modified. | |||
* '''Intercession''': This is another important feature of reflection. It is the ability for dynamic implementation of code. This can take many forms, including object creation and method calling at runtime. Again, in an inherently reflective language, these calls are made directly on the object. | |||
Examples depicting the above categories are dealt in detail, later in the chapter. | |||
The above two categories are the general types of reflection. Lets look at other categories of reflection in a different perspective. | |||
* '''Structural Reflection''': It is a quality of a program to access and modify its own structure. For example, the classes and their members constitute the structure in an object oriented language. This strucural reflection allows the possibility of accessing and modifying them. | |||
* '''Computational (Behavioral) Reflection''': As the name suggests, it is the quality of the program to dynamically access and modify the runtime behavioral of the program. For example, in object oriented languages, method calls, state of the execution stack of the threads, etc can be accessed and modified. | |||
We are concentrating on the introspection and intercession aspects of reflection in this chapter. | |||
=== Reflective languages === | === Reflective languages === | ||
Languages like LISP, CLOS, etc | Defining reflective language more precisely, a language is said to be a reflective language if it could understand reflection and possess features or tools to handle reflection explicitly. An important requirement for a reflective language is, it must have the necessary features to let access some of its features by itself (like being self-recursive). Languages like Smalltalk[[http://scg.unibe.ch/archive/papers/Duca06dMOOSEMODELS2006.pdf 4]], Ruby, Python, LISP, CLOS, etc. are reflective. | ||
Languages that are not reflective could support reflection through reflective packages. For example, languages like Java support reflection through the Java.lang.reflect package. | |||
==Reflective Language Features vs. Reflective Packages == | |||
Reflection | Lets look how the general type of reflection, ((i.e.,)introspection and intercession) is represented in reflective languages and in languages that support reflective packages.For understanding reflective language feature, lets look at reflective language Ruby and for reflective package feature lets look at the Java. | ||
Basically reflection in programming is an introspect upon itself and manipulate internal properties of the program. It also creates a way to obtain properties of Java components as they are dynamically loaded. Using the concept we can have all the information related with a class i.e. its public,private methods,fields,constructors and can create new objects ,arrays and invoke methods. We shall see these methods below and for these to work Java | |||
==Introspective Feature== | |||
===Class Based Reflection=== | |||
====Java ==== | |||
Java is so well crafted and its [http://download.oracle.com/javase/1.4.2/docs/api/java/lang/reflect/package-summary.html reflection API][[http://www.developer.com/java/web/article.php/10935_3504271_3/Java-Reflection-in-Action.htm 1]] is carefully constrained, that security is controlled simply. By learning when to use reflection and when not to, we will avoid unnecessarily complex code that can often be the result of amateurish use of reflection. In addition, you will learn to evaluate the performance of your designs, thereby ensuring the resulting code satisfying its performance requirements. | |||
This introduction describes reflection, but scarcely reveals its value in this limited space. In Java, reflection enables to discover information about the loaded classes specifically about the fields, methods and constructors, generics information, metadata annotations, etc. | |||
Basically reflection in programming is an introspect upon itself and manipulate internal properties of the program. It also creates a way to obtain properties of Java components as they are dynamically loaded. Using the concept we can have all the information related with a class i.e. its public, private methods, fields, constructors and can create new objects, arrays and invoke methods. We shall see these methods below and for these to work Java possesses the necessary reflection package. | |||
<h3> | |||
<pre> | |||
import java.lang.reflect.*; | |||
public class ClassDisplay{ | |||
public static void main(String args[]){ | |||
try{ | |||
Class c=Class.forName("java.util.Stack"); // gets the class for the given class type | |||
Method m[]=c.getDeclaredMethods(); // gives all the public,private,protected methods declared in a class. | |||
for(int i=0;i<m.length ;i++) | |||
System.out.println(m[i].toString()); | |||
}catch(Throwable e){System.err.println(e); } | |||
} | |||
} | |||
</pre> | |||
<pre> | |||
//Output displays the return object type and parameter object type together with the method name | |||
public synchronized java.lang.Object java.util.Stack.pop() | |||
public java.lang.Object java.util.Stack.push(java.lang.Object) | |||
public boolean java.util.Stack.empty() | |||
public synchronized java.lang.Object java.util.Stack.peek() | |||
public synchronized int java.util.Stack.search(java.lang.Object) | |||
</pre> | |||
</h3> | |||
====Ruby==== | |||
Ruby has reflective feature built in its language. There are no extra packages needed to explore its reflective feature. Below are some examples which explains about the introspective behavior of Ruby. Knowing each object and its properties is one type of reflection. Additionally, Ruby enables us to look at the hierarchy of each class too. | |||
<h3> | |||
<pre> | |||
puts Fixnum.ancestors # gives all the ancestors of Fixnum class | |||
</pre> | |||
</h3> | |||
The output of this is : | |||
Fixnum, Integer, Precision, Numeric, Comparable, Object, Kernel which displays all its ancestors | |||
To know about the various methods defined in a class the following lines of give more detail into it: | |||
<h3> | |||
<pre> | |||
class Demo | |||
private | |||
def privMethod | |||
end | |||
protected | |||
def protMethod | |||
end | |||
public | |||
def pubMethod | |||
end | |||
def Demo.classMethod | |||
end | |||
CONST = 1.23 | |||
end | |||
puts Demo.private_instance_methods # give output as privMethod | |||
puts Demo.public_instance_methods # protMethod | |||
puts Demo.protected_instance_methods # pubMethod | |||
puts Demo.singleton_methods # classMethod | |||
puts Demo.constants # CONST | |||
</pre> | |||
</h3> | |||
== | ===Method based reflection=== | ||
====Java==== | |||
Java's method can be accessed via the same reflection package as above. Below explains the way to access methods in Java. | |||
<h3> | |||
<pre> | |||
import java.lang.reflect.*; | import java.lang.reflect.*; | ||
public class MethodDisplay{ | public class MethodDisplay{ | ||
Line 133: | Line 144: | ||
try{ | try{ | ||
Class cls= Class.forName("MethodDisplay"); | Class cls= Class.forName("MethodDisplay"); | ||
Method meth[]= cls.getDeclaredMethods(); | Method meth[]= cls.getDeclaredMethods(); // get all the public,private,protected methods declared in a class | ||
for(int i=0;i<meth.length;i++) | for(int i=0;i<meth.length;i++) | ||
{ | { | ||
Method m=meth[i]; | Method m=meth[i]; | ||
System.out.println("Method Name: "+m.getName()); | System.out.println("Method Name: "+m.getName()); // gives the method name | ||
System.out.println("Method Declared class : "+m.getDeclaringClass()); | System.out.println("Method Declared class : "+m.getDeclaringClass());// gives the class name where the method is declared | ||
Class prec[]=m.getParameterTypes(); | Class prec[]=m.getParameterTypes(); //gives all the parameters of a method | ||
System.out.println("Method Exception Types : "+m.getExceptionTypes()); | System.out.println("Method Exception Types : "+m.getExceptionTypes()); | ||
System.out.println("Method Return Type : "+ m.getReturnType()); | System.out.println("Method Return Type : "+ m.getReturnType()); // gives the return type in a method. | ||
} | } | ||
}catch(Throwable e){System.err.println(e);} | }catch(Throwable e){System.err.println(e);} | ||
} | } | ||
} | } | ||
</pre> | |||
</h3> | |||
'''Output for above code which displays the methods declared :''' | |||
<h3> | |||
<pre> | |||
Method Name: f1 | |||
Method Declared class : class MethodDisplay | |||
Method Exception Types : [Ljava.lang.Class;@3e25a5 | |||
Method Return Type : int | |||
Method Name: main | |||
Method Declared class : class MethodDisplay | |||
Method Exception Types : [Ljava.lang.Class;@19821f | |||
Method Return Type : void | |||
</pre> | |||
</h3> | |||
Similarly we can get information about the fields declared in a class with the help of methods like getField(String name), getFields(), getDeclaredField(String name), getDeclaredFields().The same technique used for Constructor information retrieval. | |||
====Ruby==== | |||
Ruby supports liberated objects. We really cannot tell exactly what an object can do until you look under its hood. For instance, we can get a list of all the methods to which an object will respond. | |||
<h3> | |||
<pre> | |||
r = 1..10 # r is a range object | |||
list = r.methods # this is a way to get all the methods in an array that can be invoked in the object. | |||
</pre> | |||
</h3> | |||
We can also determine the object's class from it by using the kind_of? method. | |||
<h3> | |||
<pre> | |||
num = 1 | |||
num.class # Fixnum | |||
num.kind_of? # Fixnum | |||
</pre> | |||
</h3> | |||
==Intercessive Feature == | |||
Intercessive is process of invoking dynamically on a class at run time. The previous section just talked about the ways to get information about a class. Intercessive enables to use the metaobjects to their instances in run time environment. E.g. Method.invoke(Object o, Object… args) | |||
===Method Invocation=== | |||
===Java=== | |||
With the Java reflection API, we can interrogate an object to get all sorts of information about its class.Lets see the technique how Java helps to invoke a method defined in a class at runtime using reflection API. | |||
<h3> | |||
<pre> | |||
import java.lang.reflect.*; | |||
public class MethodInvoke{ | |||
public int add(int a,int b){ | |||
return a+b; | |||
} | |||
public static void main(String args[]){ | |||
try{ | |||
Class cls= Class.forName("MethodInvoke"); | |||
Class partypes[]= new Class[2]; | |||
partypes[0]= Integer.TYPE; | |||
partypes[1]=Integer.TYPE; | |||
Method meth=cls.getDeclaredMethod("add",partypes); | |||
MethodInvoke MI = new MethodInvoke(); | |||
Object arglist[]=new Object [2]; | |||
arglist[0]=new Integer(37); | |||
arglist[1]=new Integer(47); | |||
Object retobj = meth.invoke(MI, arglist); // method invocation with class object and list of input parameters | |||
Integer retval = (Integer)retobj ; | |||
System.out.println("Value :"+ retval); | |||
}catch (Exception e){} | |||
} | |||
} | |||
</pre> | |||
</h3> | |||
First we get the method declared and then we invoke the method by calling Method.invoke(*) . This accepts a class object where the method is declared along with the parameter list defined in an array. | |||
=== Ruby === | |||
Ruby methods are invoked by three methods apart from using the object to call its methods. The three methods are defined with example below: | |||
=====Way 1:===== | |||
<h3> | |||
<pre> | |||
"John Coltrane".send(:length) # 13 | |||
"Miles Davis".send("sub", /iles/, '.') # M. Davis | |||
</pre> | |||
</h3> | |||
=====Way 2:===== | |||
The string object uses "send " command to invoke its length method and also its sub method to replace the letters 'iles' with '.' Another way of invoking methods dynamically uses ''method'' objects. A method object is like a Proc object: it represents a chunk of code and a context in which it executes. Once we have the method object, we can execute it sometime later by sending it the message call. | |||
<h3> | |||
<pre> | |||
trane = "John Coltrane".method(:length) | |||
miles = "Miles Davis".method("sub") | |||
trane.call → 13 # 13 | |||
miles.call(/iles/, '.') # M. Davis | |||
</pre> | |||
</h3> | |||
=====Way 3:===== | |||
Another way to invoke the method dynamically is by eval method. Eval will parse and execute an arbitrary string of legal Ruby source code. | |||
<h3> | |||
<pre> | |||
trane = %q{"John Coltrane".length} | |||
miles = %q{"Miles Davis".sub(/iles/, '.')} | |||
eval trane # 13 | |||
eval miles # M. Davis | |||
</pre> | |||
</h3> | |||
===Dynamic array Manipulation === | |||
====Java==== | |||
<h3> | |||
<pre> | |||
import java.lang.reflect.*; | |||
public class ArrayManipulation { | |||
public static void main(String args[]){ | |||
try{ | |||
Class cls= Class.forName("java.lang.String"); | |||
Object arr= Array.newInstance(cls, 10); // creating new instance of an array | |||
Array.set(arr,5,"this is a reflection test"); | |||
String s =(String)Array.get(arr,5); | |||
System.out.println("Returned String :" + s); | |||
}catch (Exception e){} | |||
} | |||
} | |||
</pre> | |||
</h3> | |||
Arrays are declared and initiliazed dynamically with the help of Reflection. An new array instance cannot be created till we know the size of the array. But this is not the case with reflection. It helps us to dynamically create arrays. Reflection package provides with Array class which has newInstance method that allows to create arrays for a particular class and size. This is one of the major merits of reflection in Java. | |||
====Ruby==== | |||
Creating array in ruby is very simple and it can be done dynamically. Elements in array can be added dynamically and unlike in java the array can be expanded. | |||
<h3> | |||
<pre> | |||
arr=Array.new | |||
Array.new(2) => creates an array of size 2 | |||
Array.new(5, "A") => creates an array of size 5 and defaults every value to "A" | |||
arr << [56,78,2] => appends another array to the end of arr array. | |||
arr + Array.new (10, "Hello") => It is a concatenation operation which returns a third array by concatenating two arrays. | |||
</pre> | |||
</h3> | |||
== Advantages and Disadvantages of reflection[[http://www.di.uniovi.es/ooosws2001/papers/ortin_final.pdf 3]] == | |||
<table> | |||
<tr> | |||
<td> | |||
'''Advantages''' | |||
</td> | |||
</tr> | |||
<tr> | |||
<td> | |||
* Generated code is generally more readable and debuggable for developers. | |||
</td> | |||
</tr> | |||
<tr> | |||
<td> | |||
* Reflexive procedures fail more often at runtime than during compilation. | |||
</td> | |||
</tr> | |||
<tr> | |||
<td> | |||
* Without it, our solutions are messy and weak. | |||
</td> | |||
</tr> | |||
<tr> | |||
<td> | |||
* Enables more flexibility and versatility. | |||
</td> | |||
</tr> | |||
</table> | |||
<table> | |||
<tr> | |||
<td> | |||
'''Disadvantages'''</td> | |||
</tr> | |||
<tr> | |||
<td> | |||
* The loading class might need frequent updates and regenerations. Maintenance is a setback.</td> | |||
</tr> | |||
<tr> | |||
<td> | |||
* Certain Java JVM might not be able to perform dynamic resolving which leads to performance setback.</td> | |||
</tr> | |||
<tr> | |||
<td> | |||
*A runtime permission is required which may not be present when running under a security manager.</td> | |||
</tr> | |||
<tr> | |||
<td> | |||
* Unexpected side-effects due to illegal access of private fields and methods, which may render code dysfunctional and may destroy portability.</td> | |||
</tr> | |||
</table> | |||
== Conclusion == | |||
Reflection enables the programs to be more flexible, versatile and helps in dynamic resolving of the programmatic features. The introspection and intercession features allow the program to know and modify itself. These features are supported and implemented differently in reflective languages and languages with reflective packages. They are language specific and also vary with each package. | |||
== References == | == References == | ||
http://www. | # [http://www.developer.com/java/web/article.php/10935_3504271_3/Java-Reflection-in-Action.htm Ira R. Forman, Nate Forman. Java Reflection in Action. Manning Publications Co., October, 2004.] | ||
http://www.cs.indiana.edu/~jsobel/rop.html | # [http://www.cs.indiana.edu/~jsobel/rop.html Jonathan M. Sobel Daniel P. Friedman. An Introduction to Reflection-Oriented Programming. Computer Science Department, Indiana University.] | ||
# [http://www.di.uniovi.es/ooosws2001/papers/ortin_final.pdf Francisco Ortín Soler, Juan Manuel Cueva Lovelle. Building a Completely Adaptable Reflective System. Campus Llamaquique.] | |||
http://www.di.uniovi.es/ooosws2001/papers/ortin_final.pdf | # [http://scg.unibe.ch/archive/papers/Duca06dMOOSEMODELS2006.pdf Stephane Ducasse, Tudor Girba1. Using Smalltalk as a Reflective Executable Meta-Language. Models 2006.] | ||
# [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.158.2012&rep=rep1&type=pdf Eric Tanter. Reflection and Open Implementations. July, 1991.] | |||
http://scg.unibe.ch/archive/papers/Duca06dMOOSEMODELS2006.pdf | # [http://www.ub.uni-konstanz.de/kops/volltexte/2002/803/pdf/DissertationEgbertAlthammer.pdf Egbert Althammer. Reflection Patterns in the Context of Object and Component Technology. Konstanz, 2001.] | ||
# [http://www.laputan.org/reflection/ooffrmla.html Brian Foote. An Object-Oriented Framework For Reflective Metalevel Architectures, 1994.] | |||
http://www.ub.uni-konstanz.de/kops/volltexte/2002/803/pdf/DissertationEgbertAlthammer.pdf | # [http://pg-server.csc.ncsu.edu/mediawiki/index.php/CSC/ECE_517_Fall_2010/ch4_4g_km Metaprogramming in dynamically typed languages] | ||
http://www.laputan.org/reflection/ooffrmla.html |
Latest revision as of 18:00, 23 November 2010
Reflective Language Features vs. Reflective Packages
Definition
Reflection is the integral quality of a program to dynamically manipulate its own state. More specifically, the program can infer and modify itself by making use of the representation of its own state. The state of a program can be its implementation[5] aspects like syntax, semantics, structure, etc. The program acts through its self-accessible state and takes itself as its domain to be acted upon. Programming languages that possess this quality are said to be reflective.[2]
Most object-oriented languages support some form of reflection. Smalltalk, Ruby, and Python in particular have very powerful and flexible reflection mechanisms. Java[6] also supports reflection, but not as flexible and dynamic fashion as the others. C++ does not support reflection as we've defined it here, but it does support a limited form of run-time type information that allows a program to determine the type of an object at run-time. Eiffel also has support for a limited form of reflection, although it is much improved in the most recent versions of Eiffel, including the ability to determine the features contained in an object.
Consider a simple example of Reflection in Java below :
public class HelloWorld {
public void printName() {
System.out.println(this.getClass().getName());
}
}
The line (obj.HelloWorld()).printName(); sends the string 'HelloWorld' to the standard output. Let obj be an object of HelloWorld or one of its subclasses. When the program reaches the line, obj.printName(); it sends the name of the class to the standard output.
This simple example denotes an effective feature. The printName method looks at the object obj for its class (this.getClass()). It decides what to print by delegating to the object's class in runtime.(i.e.,) the printName method behaves differently for each subclass of HelloWorld. The method is so flexible that it dynamically adapts itself to the class or subclass that inherits it.
Reflection being an effective language feature enables metaprogramming[7]. A reflective system would possess the feature of allowing programmers to design, create make use of the objects to act dynamically based on an existing part of the running system. Thus, reflection can also be defined as a feature where a programming language behaves like its own metalanguage. It contains metadata and associated operations to manipulate it in runtime.
Another important concept that is closely associated with reflection is reification. Reification is the process of packaging the information about the environment suitable so that it can be manipulated(by reflection).
Reflective mechanisms
Reflection is a feature that is made available in a language that facilitatates either reification or reflection or both.
Categorizing Reflection
There two primary criteria to categorize reflective systems. These criteria are based on when reflection happens and what is reflected. Considering what is being reflected, the categories of reflective systems are :
- Introspection: This is the ability of the program to identify the type of an object and its methods. Here, the structure is identified and accessed but not modified.
- Intercession: This is another important feature of reflection. It is the ability for dynamic implementation of code. This can take many forms, including object creation and method calling at runtime. Again, in an inherently reflective language, these calls are made directly on the object.
Examples depicting the above categories are dealt in detail, later in the chapter. The above two categories are the general types of reflection. Lets look at other categories of reflection in a different perspective.
- Structural Reflection: It is a quality of a program to access and modify its own structure. For example, the classes and their members constitute the structure in an object oriented language. This strucural reflection allows the possibility of accessing and modifying them.
- Computational (Behavioral) Reflection: As the name suggests, it is the quality of the program to dynamically access and modify the runtime behavioral of the program. For example, in object oriented languages, method calls, state of the execution stack of the threads, etc can be accessed and modified.
We are concentrating on the introspection and intercession aspects of reflection in this chapter.
Reflective languages
Defining reflective language more precisely, a language is said to be a reflective language if it could understand reflection and possess features or tools to handle reflection explicitly. An important requirement for a reflective language is, it must have the necessary features to let access some of its features by itself (like being self-recursive). Languages like Smalltalk[4], Ruby, Python, LISP, CLOS, etc. are reflective.
Languages that are not reflective could support reflection through reflective packages. For example, languages like Java support reflection through the Java.lang.reflect package.
Reflective Language Features vs. Reflective Packages
Lets look how the general type of reflection, ((i.e.,)introspection and intercession) is represented in reflective languages and in languages that support reflective packages.For understanding reflective language feature, lets look at reflective language Ruby and for reflective package feature lets look at the Java.
Introspective Feature
Class Based Reflection
Java
Java is so well crafted and its reflection API[1] is carefully constrained, that security is controlled simply. By learning when to use reflection and when not to, we will avoid unnecessarily complex code that can often be the result of amateurish use of reflection. In addition, you will learn to evaluate the performance of your designs, thereby ensuring the resulting code satisfying its performance requirements.
This introduction describes reflection, but scarcely reveals its value in this limited space. In Java, reflection enables to discover information about the loaded classes specifically about the fields, methods and constructors, generics information, metadata annotations, etc.
Basically reflection in programming is an introspect upon itself and manipulate internal properties of the program. It also creates a way to obtain properties of Java components as they are dynamically loaded. Using the concept we can have all the information related with a class i.e. its public, private methods, fields, constructors and can create new objects, arrays and invoke methods. We shall see these methods below and for these to work Java possesses the necessary reflection package.
import java.lang.reflect.*;
public class ClassDisplay{
public static void main(String args[]){
try{
Class c=Class.forName("java.util.Stack"); // gets the class for the given class type
Method m[]=c.getDeclaredMethods(); // gives all the public,private,protected methods declared in a class.
for(int i=0;i<m.length ;i++)
System.out.println(m[i].toString());
}catch(Throwable e){System.err.println(e); }
}
}
//Output displays the return object type and parameter object type together with the method name
public synchronized java.lang.Object java.util.Stack.pop()
public java.lang.Object java.util.Stack.push(java.lang.Object)
public boolean java.util.Stack.empty()
public synchronized java.lang.Object java.util.Stack.peek()
public synchronized int java.util.Stack.search(java.lang.Object)
Ruby
Ruby has reflective feature built in its language. There are no extra packages needed to explore its reflective feature. Below are some examples which explains about the introspective behavior of Ruby. Knowing each object and its properties is one type of reflection. Additionally, Ruby enables us to look at the hierarchy of each class too.
puts Fixnum.ancestors # gives all the ancestors of Fixnum class
The output of this is : Fixnum, Integer, Precision, Numeric, Comparable, Object, Kernel which displays all its ancestors
To know about the various methods defined in a class the following lines of give more detail into it:
class Demo
private
def privMethod
end
protected
def protMethod
end
public
def pubMethod
end
def Demo.classMethod
end
CONST = 1.23
end
puts Demo.private_instance_methods # give output as privMethod
puts Demo.public_instance_methods # protMethod
puts Demo.protected_instance_methods # pubMethod
puts Demo.singleton_methods # classMethod
puts Demo.constants # CONST
Method based reflection
Java
Java's method can be accessed via the same reflection package as above. Below explains the way to access methods in Java.
import java.lang.reflect.*;
public class MethodDisplay{
private int f1(Object p,int x) throws NullPointerException {
if(p==null){
throw new NullPointerException();}
return x;
}
public static void main(String args[]){
try{
Class cls= Class.forName("MethodDisplay");
Method meth[]= cls.getDeclaredMethods(); // get all the public,private,protected methods declared in a class
for(int i=0;i<meth.length;i++)
{
Method m=meth[i];
System.out.println("Method Name: "+m.getName()); // gives the method name
System.out.println("Method Declared class : "+m.getDeclaringClass());// gives the class name where the method is declared
Class prec[]=m.getParameterTypes(); //gives all the parameters of a method
System.out.println("Method Exception Types : "+m.getExceptionTypes());
System.out.println("Method Return Type : "+ m.getReturnType()); // gives the return type in a method.
}
}catch(Throwable e){System.err.println(e);}
}
}
Output for above code which displays the methods declared :
Method Name: f1
Method Declared class : class MethodDisplay
Method Exception Types : [Ljava.lang.Class;@3e25a5
Method Return Type : int
Method Name: main
Method Declared class : class MethodDisplay
Method Exception Types : [Ljava.lang.Class;@19821f
Method Return Type : void
Similarly we can get information about the fields declared in a class with the help of methods like getField(String name), getFields(), getDeclaredField(String name), getDeclaredFields().The same technique used for Constructor information retrieval.
Ruby
Ruby supports liberated objects. We really cannot tell exactly what an object can do until you look under its hood. For instance, we can get a list of all the methods to which an object will respond.
r = 1..10 # r is a range object
list = r.methods # this is a way to get all the methods in an array that can be invoked in the object.
We can also determine the object's class from it by using the kind_of? method.
num = 1
num.class # Fixnum
num.kind_of? # Fixnum
Intercessive Feature
Intercessive is process of invoking dynamically on a class at run time. The previous section just talked about the ways to get information about a class. Intercessive enables to use the metaobjects to their instances in run time environment. E.g. Method.invoke(Object o, Object… args)
Method Invocation
Java
With the Java reflection API, we can interrogate an object to get all sorts of information about its class.Lets see the technique how Java helps to invoke a method defined in a class at runtime using reflection API.
import java.lang.reflect.*;
public class MethodInvoke{
public int add(int a,int b){
return a+b;
}
public static void main(String args[]){
try{
Class cls= Class.forName("MethodInvoke");
Class partypes[]= new Class[2];
partypes[0]= Integer.TYPE;
partypes[1]=Integer.TYPE;
Method meth=cls.getDeclaredMethod("add",partypes);
MethodInvoke MI = new MethodInvoke();
Object arglist[]=new Object [2];
arglist[0]=new Integer(37);
arglist[1]=new Integer(47);
Object retobj = meth.invoke(MI, arglist); // method invocation with class object and list of input parameters
Integer retval = (Integer)retobj ;
System.out.println("Value :"+ retval);
}catch (Exception e){}
}
}
First we get the method declared and then we invoke the method by calling Method.invoke(*) . This accepts a class object where the method is declared along with the parameter list defined in an array.
Ruby
Ruby methods are invoked by three methods apart from using the object to call its methods. The three methods are defined with example below:
Way 1:
"John Coltrane".send(:length) # 13
"Miles Davis".send("sub", /iles/, '.') # M. Davis
Way 2:
The string object uses "send " command to invoke its length method and also its sub method to replace the letters 'iles' with '.' Another way of invoking methods dynamically uses method objects. A method object is like a Proc object: it represents a chunk of code and a context in which it executes. Once we have the method object, we can execute it sometime later by sending it the message call.
trane = "John Coltrane".method(:length)
miles = "Miles Davis".method("sub")
trane.call → 13 # 13
miles.call(/iles/, '.') # M. Davis
Way 3:
Another way to invoke the method dynamically is by eval method. Eval will parse and execute an arbitrary string of legal Ruby source code.
trane = %q{"John Coltrane".length}
miles = %q{"Miles Davis".sub(/iles/, '.')}
eval trane # 13
eval miles # M. Davis
Dynamic array Manipulation
Java
import java.lang.reflect.*;
public class ArrayManipulation {
public static void main(String args[]){
try{
Class cls= Class.forName("java.lang.String");
Object arr= Array.newInstance(cls, 10); // creating new instance of an array
Array.set(arr,5,"this is a reflection test");
String s =(String)Array.get(arr,5);
System.out.println("Returned String :" + s);
}catch (Exception e){}
}
}
Arrays are declared and initiliazed dynamically with the help of Reflection. An new array instance cannot be created till we know the size of the array. But this is not the case with reflection. It helps us to dynamically create arrays. Reflection package provides with Array class which has newInstance method that allows to create arrays for a particular class and size. This is one of the major merits of reflection in Java.
Ruby
Creating array in ruby is very simple and it can be done dynamically. Elements in array can be added dynamically and unlike in java the array can be expanded.
arr=Array.new
Array.new(2) => creates an array of size 2
Array.new(5, "A") => creates an array of size 5 and defaults every value to "A"
arr << [56,78,2] => appends another array to the end of arr array.
arr + Array.new (10, "Hello") => It is a concatenation operation which returns a third array by concatenating two arrays.
Advantages and Disadvantages of reflection[3]
Advantages |
|
|
|
|
Disadvantages |
|
|
|
|
Conclusion
Reflection enables the programs to be more flexible, versatile and helps in dynamic resolving of the programmatic features. The introspection and intercession features allow the program to know and modify itself. These features are supported and implemented differently in reflective languages and languages with reflective packages. They are language specific and also vary with each package.
References
- Ira R. Forman, Nate Forman. Java Reflection in Action. Manning Publications Co., October, 2004.
- Jonathan M. Sobel Daniel P. Friedman. An Introduction to Reflection-Oriented Programming. Computer Science Department, Indiana University.
- Francisco Ortín Soler, Juan Manuel Cueva Lovelle. Building a Completely Adaptable Reflective System. Campus Llamaquique.
- Stephane Ducasse, Tudor Girba1. Using Smalltalk as a Reflective Executable Meta-Language. Models 2006.
- Eric Tanter. Reflection and Open Implementations. July, 1991.
- Egbert Althammer. Reflection Patterns in the Context of Object and Component Technology. Konstanz, 2001.
- Brian Foote. An Object-Oriented Framework For Reflective Metalevel Architectures, 1994.
- Metaprogramming in dynamically typed languages