CSC/ECE 517 Fall 2012/ch1 1w5 su: Difference between revisions
No edit summary |
No edit summary |
||
Line 141: | Line 141: | ||
will display "This is a new method". If another Sample object is created, this new object will not have access to the anothermethod method because that method was only added to a specific instance of the Sample class. In Java, methods cannot be created on existing objects (because it is a statically typed language), so this kind of reflection is not possible. | will display "This is a new method". If another Sample object is created, this new object will not have access to the anothermethod method because that method was only added to a specific instance of the Sample class. In Java, methods cannot be created on existing objects (because it is a statically typed language), so this kind of reflection is not possible. | ||
= Advantages and Disadvantages = | |||
== Advantages == | |||
#Access to metadata and ability to manipulate classes: | |||
You can access the metadata of classes and methods, get the annotations and analyze them. Writing direct code is based on depending on specific class details (like interface, | |||
method or field names) known at compile-time. If we need to write code that | |||
depends on class details known only at runtime, then reflection comes handy. | |||
#Creating Adaptable and Flexible Solutions: | |||
Because of its dynamic nature, reflection is useful for creating adaptable and | |||
flexible software that is often not possible with direct code. Theoretically, it is | |||
well known that reflection can help add more dynamism and flexibility to | |||
frameworks and design patterns. | |||
# '''Writing Tools that Require Implementation Details''': Many of the developer tools need access to internal or implementation details of the code For example, an intelligent text editor can query a class using reflection | |||
and get details about its implementation, which can be very helpful. When user | |||
types in an object name and a ‘.’ to access a member, the text editor can pop with a | |||
list box with list of accessible members (obtained using reflection) that the | |||
programmer can select from | |||
# '''Signature-Based Polymorphism''': Java and C# programmers are familiar with polymorphism based on interface | |||
inheritance. Reflection provides an alternative where we can invoke methods having | |||
same signature, from different classes not have a common interface (which is | |||
required in interface based polymorphism). | |||
=Conclusion= | =Conclusion= |
Revision as of 17:05, 10 September 2012
Reflective Language Features vs Reflective Packages
Reflection is the ability of a computer program to examine and modify the structure and behavior (specifically the values, meta-data, properties and functions) of an object at runtime.<ref>Reflection on Wikipedia</ref>
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. <ref>An Introduction to Reflection-Oriented Programming - J.M. Sobel , Daniel P. Friedman - 1996</ref>
A reflective language is a programming language that has been architected to allow reflection. This means the language was constructed to "'reason' effectively and consequentially about its own inference process."[2] Reflection provides languages with versatility [5] and flexibility [3]. Languages that are not reflective can incorporate some of the features of reflection by using reflective packages. For example, Java includes a reflective package called "java.lang.reflect."
Brief History of Reflection
Year | Development <ref>Java Reflection - Ken Cooney</ref> |
---|---|
Jun 1976 | Origin of Reflective Programming:
The idea of reflection came to Brian Smith at the Xerox Palo Alto Research Center. Smith was working on the KRL <ref>Knowledge Representation Language(KRL)</ref> representation language and as an exercise to learn the language, he worked on a project to represent KRL in KRL. He reasoned that this would be a good way to learn the language since he had to both use and mention the language. He worked on it long enough to become intrigued with the thought of building a system that was self-descriptive. In the five years since, Smith worked on initial versions of such a language, which he called MANTIQ. |
1982 | Brian Cantwell Smith writes a doctoral dissertation at MIT introducing the notion of computational reflection. 3-LISP is the first official programming language to use reflection. <ref> Brian Cantwell Smith, "Procedural Reflection in Programming Languages", Massachusetts Institute of Technology, Feb 1982 </ref> |
1983 | Smalltalk v1.0 has 75% of the standard Reflection command language. <ref>[ http://tinyurl.com/smalltalk-infoworld ]</ref> |
1984 | The Interim 3-LISP Reference Manual is published, co authored by Brian Cantwell Smith. |
1987 | Smalltalk v2.0 adds the rest of the Reflection. |
1987-89 | Perl |
Oct 1996 | Visual J++ and C# has reflections. Python v1.4 |
Feb 1997 | Java Reflections (JDK v1.1) |
Feb 1998 | Python v1.5 makes it easier for reflective programming. |
Jul 2004 | PHP v5.0 |
Reflective Language Features vs Reflective Packages
The features of a reflective language can be broadly categorized as either introspection or intercession. "Introspection is the ability for a program to observe and therefore reason about its own state. Intercession is the ability for a program to modify its own execution state or alter its own interpretation or meaning."[4]
Introspection is what allows the program to "know" information about itself. This can include an object knowing what kind of object it is, and what methods it has. Intercession is what allows a program to change behavior based on that information. This can include calling methods dynamically, which means that the actual method that is called on an object is decided when the program is running, and not when the program is compiled. Another introspective feature granted by reflection is the ability for, when methods are added to an object when the program is running, these methods can be called.
While the behavior between a program written in a reflective language and a program written with a reflective package will be similar, how the features are implemented will differ. In a reflective language, you can access the information about an object or class from the object or class. In a language with a reflective package, functionality is provided through intermediary objects. For the following examples, Ruby will be used to illustrate how the features of reflection are implemented in a reflective language and Java will be used to illustrate how the features of reflection are implemented in a language with a reflective package.
Introspective features
One of the most powerful features that reflection provides is the ability, given an object, to know what kind of object it is, and what methods it contains. In a reflective language, like Ruby, that is done by directly querying the object. For example, with the given class:
class Sample #empty class end samp = Sample.new
The call:
puts samp.class
will list "Sample" as the class and the call:
puts samp.methods
will list the methods that Sample has (which will include all the methods in Sample's superclass – Object). In a language with a reflective package, like Java, the package is not automatically included in the functionality. It must be imported with:
import java.lang.reflect.*;
Also, for any given object A, a separate class object B, is created and B contains the information about A. For example, with the given class:
public class Sample { //Empty class }
The class information can be found by invoking:
Sample samp = new Sample(); //Create an instance of Sample Class sampClass = samp.getClass(); //Create a class object for instance of Sample System.out.println(sampClass.getName()); //Display class name
and the method list can be found with:
Method[] meth = sampClass.getMethods(); //Return array of method objects for Class object of Sample instance for (int i = 0; i < meth.length; i++){ System.out.println(meth[i]); //Display methods }
As shown in the above examples, both Ruby and Java have the same reflective feature - the ability for an object or class to "know" about itself. However, in Java, a Class object is created to access class information, and method information for the object is stored in method objects that can be accessed via the Class object. In Ruby, that information is accessed directly from the object or class in question.
Intercessive features
Another important feature granted by reflection, 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. However, when a language has a reflective package to handle reflective features, the calls are directed through a separate object. For example, in Ruby, this class:
class Sample def printOne puts 1 end def printTwo puts 2 end def printThree puts 3 end end
defines three methods that print different numbers depending on which method is called. Without reflection, calls to these methods could not be changed at runtime. However, reflection allows the method calls to depend on string values that do not have to be initialized until runtime as seen in the following code:
samp = Sample.new #Create an instance of the Sample class option="printOne" samp.send(option) #printOne method is called option="printThree" samp.send(option) #printThree method is called
What is printed from this code depends on the value of "option", which might not have a value until runtime. In this code, the call:
samp.send(option)
is the same, but the "option" value has changed and that is what determines the method that is called. This same feature exists in languages with reflective packages, but again it is accessed indirectly. For example, in Java, a similar class:
public class Sample { public void printOne(){ System.out.println("1"); } public void printTwo(){ System.out.println("2"); } public void printThree(){ System.out.println("3"); } }
handles reflection by accessing the method through a Class object and Method object:
Sample samp = new Sample(); Class sampClass = samp.getClass(); String option = "printOne"; Method meth = sampClass.getMethod(option); meth.invoke(sampClass, null); option = "printThree"; meth = sampClass.getMethod(option); meth.invoke(sampClass, null);
The result of this code is the same as the Ruby code, but to achieve it a Class object was created to retrieve information about the original object, and a Method object was created to retrieve method information from the Class object.
Some of the more dynamic intercessive features that reflection gives a programming language are possible because of the dynamic nature of the language. For example, in Ruby, a method can be added to an object that has already been instanced. Given a class "Sample", this code:
samp = Sample.new def samp.anothermethod puts "This is a new method" end
will create a method on the instance of Sample. Reflection is what allows that method to be accessed so that the call:
samp.anothermethod
will display "This is a new method". If another Sample object is created, this new object will not have access to the anothermethod method because that method was only added to a specific instance of the Sample class. In Java, methods cannot be created on existing objects (because it is a statically typed language), so this kind of reflection is not possible.
Advantages and Disadvantages
Advantages
- Access to metadata and ability to manipulate classes:
You can access the metadata of classes and methods, get the annotations and analyze them. Writing direct code is based on depending on specific class details (like interface, method or field names) known at compile-time. If we need to write code that depends on class details known only at runtime, then reflection comes handy.
- Creating Adaptable and Flexible Solutions:
Because of its dynamic nature, reflection is useful for creating adaptable and flexible software that is often not possible with direct code. Theoretically, it is well known that reflection can help add more dynamism and flexibility to frameworks and design patterns.
- Writing Tools that Require Implementation Details: Many of the developer tools need access to internal or implementation details of the code For example, an intelligent text editor can query a class using reflection
and get details about its implementation, which can be very helpful. When user types in an object name and a ‘.’ to access a member, the text editor can pop with a list box with list of accessible members (obtained using reflection) that the programmer can select from
- Signature-Based Polymorphism: Java and C# programmers are familiar with polymorphism based on interface
inheritance. Reflection provides an alternative where we can invoke methods having same signature, from different classes not have a common interface (which is required in interface based polymorphism).
Conclusion
Reflection allows the creation of more versatile and flexible programs through both introspective and intercessive features. These features include the ability for a program to know about itself, and to act on that information. As shown through the use of Ruby as a representative of a reflective language and Java as a representative of a language with a reflective package, these features are implemented differently.
References
[2] Smith, Brian Caldwell 1982 Procedural Reflection in Programming Languages MIT Press, Cambridge, MA
Additional Information
McHale, Ciaran 2008 Java Reflection Explained Simply
References
<references />