CSC/ECE 517 Fall 2011/ch4 4f rs: Difference between revisions
(25 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
==Introduction== | ==Introduction== | ||
Reflection is a relatively common computer programming concept where in the program has the | [http://en.wikipedia.org/wiki/Reflection_%28computer_programming%29 Reflection ]is a relatively common [http://en.wikipedia.org/wiki/Computer_programming computer programming] concept where in the program has the inherent ability to examine itself at run time. Based on its observations the program can modify it's behavior for the given situation.The modifications can be any aspect of the programming language .i.e syntax, semantics, or implementation. | ||
Reflection as a concept was first introduced in the doctoral dissertation of Dr. Brian Cantwell Smith in 1992. | Reflection as a concept was first introduced in the doctoral dissertation of Dr. Brian Cantwell Smith<ref>[http://hdl.handle.net/1721.1/15961 Brian Cantwell Smith, Procedural Reflection in Programming Languages, Department of Electrical Engineering and Computer Science, Massachusetts Institute of Technology, PhD Thesis, 1982.]</ref><ref>[http://publications.csail.mit.edu/lcs/specpub.php?id=840 Brian C. Smith. Reflection and semantics in a procedural language. Technical Report MIT-LCS-TR-272, Massachusetts Institute of Technology, Cambridge, Mass., January 1982.]</ref> in 1992. | ||
==Reflection== | ==Reflection== | ||
Line 19: | Line 19: | ||
Some of the common information that can be obtained from reflection are : | Some of the common information that can be obtained from reflection are : | ||
* Object type | * Object type | ||
* Super classes of any class | * [http://en.wikipedia.org/wiki/Superclass_%28computer_science%29#Subclasses_and_superclasses Super classes] of any class | ||
* Methods | * [http://en.wikipedia.org/wiki/Method_(computer_programming) Methods] | ||
* class fields | * class fields | ||
* Interfaces | * [http://download.oracle.com/javase/tutorial/java/concepts/interface.html Interfaces] | ||
Common languages that exhibit reflection to varying degrees are Ruby, Java, Smalltalk, C# and more. | Common languages that exhibit reflection to varying degrees are Ruby, Java, Smalltalk, C# and more. | ||
Line 32: | Line 32: | ||
==Implementation== | ==Implementation== | ||
There are many challenges faced by designers of reflective languages. They must provide as much leeway as possible for late binging and at the same time they must optimize the compilation of the static components so that they are ready for run-time. Reflection is in essense a connection between the object-level (program) and meta-level (the processor). The ability of the object level to be able to observe and modify the meta-level information is the consequence of this connection. These actions can be termed as introspection and intercession. These actions can implemented with the implementation of the following components: | There are many challenges faced by designers of reflective languages. They must provide as much leeway as possible for late binging and at the same time they must optimize the compilation of the static components so that they are ready for run-time. Reflection is in essense a connection between the object-level (program) and meta-level (the processor). The ability of the object level to be able to observe and modify the meta-level information is the consequence of this connection. These actions can be termed as [http://en.wikipedia.org/wiki/Type_introspection introspection] (This involves the action of observing the class) and intercession (this involves the operation of modifying the behavior of the class). These actions can implemented with the implementation of the following components: | ||
* Ability to create [http://en.wikipedia.org/wiki/First-class_object first class objects] ie [http://en.wikipedia.org/wiki/Reification_(computer_science) reification]. | * Ability to create [http://en.wikipedia.org/wiki/First-class_object first class objects] ie [http://en.wikipedia.org/wiki/Reification_(computer_science) reification]. | ||
Line 41: | Line 41: | ||
==Reflection by example== | ==Reflection by example== | ||
===C#=== | |||
<pre> | |||
int val = 20; | |||
System.Type type = val.GetType(); | |||
System.Console.WriteLine(type); | |||
</pre> | |||
Output is type of the variable "val" = System.Int32 | |||
===Smalltalk=== | |||
<pre> | |||
w := Workspace new. | |||
w openLabel:'My Workspace' | |||
w inspect | |||
</pre> | |||
Here we can inspect all the methods available to the instance 'w'. | |||
===Java=== | |||
<pre> | |||
import java.lang.reflect.*; | |||
public class Fclass{ | |||
public static void main(String[] args){ | |||
Class cls = java.lang.Integer.class; | |||
String info; | |||
info = cls.getName(); // It will show java.lang.Integer | |||
System.out.println(info); | |||
} | |||
} | |||
</pre> | |||
cls.getName() gives the complete class name which is printed out as the output of the above code is "java.lang.Integer" | |||
===PHP=== | |||
<pre> | |||
$reflector = new ReflectionClass("SimpleXMLElement"); | |||
echo $reflector; | |||
</pre> | |||
Output of this example is the complete class map of the class SimpleXMLElement. | |||
==Dynamic binding : Making reflection possible== | |||
Ruby implements [http://en.wikipedia.org/wiki/Dynamic_dispatch dynamic binding] of objects. Dynamic binding plays a very important role in [http://en.wikipedia.org/wiki/Metaprogramming meta-programming]. | |||
In languages like C,C++; a simple assignment "a = b", would require 'a' and 'b' to be of the same type. The assignment is interpreted as copying b into a and is implemented by copying the contents of b into the space occupied by a. Thus if 'a' had been declared as an object whose memory size is less than b's object, then object slicing takes place i.e. only that part of 'b' which fits into a's memory would be copied. This behavior might lead to unintended consequences. | |||
[[File:Slicing.gif]] | |||
But dynamic binding in Ruby ensures that the type of object stored in a variable is determined at run time and not at compile time. Thus the assignment "a = b" is interpreted as binding 'a' to the same object that 'b' is bound to. It is implemented by copying the reference stored in b into the (pointer-sized) memory cell of 'a'. Thus 'a' and 'b' point to the same object after the assignment. | |||
[[File:Before_binding.png]] [[File:After_binding.png]] | |||
==Symbols and their usage in reflection techniques== | |||
===Basics=== | |||
[http://en.wikipedia.org/wiki/Symbol_%28programming%29 Symbols] are objects used to represent names and strings inside a Ruby [http://en.wikipedia.org/wiki/Interpreter_%28computing%29 interpreter]. They are immutable and remain unique i.e. every instance of a particular symbol is the same symbol. | |||
===Usage in reflection techniques=== | |||
Symbols are widely used in reflection to invoke methods dynamically. Reflection methods like 'respond_to', 'send' make use of symbols as a reference to other methods. Strings can also be used in place of symbols. However symbols are more efficient compared to strings in terms of memory and performance. | |||
===Examples=== | |||
====Passing method by reference using a symbol==== | |||
<pre> | |||
class Float | |||
def poly | |||
self*self*self + 2*self*self + 3*self + 4 | |||
end | |||
end | |||
</pre> | |||
And we can pass poly to an integration routine: | |||
<pre> | |||
area = integrate(:poly, 0, 10) | |||
</pre> | |||
====Symbols in reflection==== | |||
[http://ruby-doc.org/core-1.9.2/Object.html#method-i-send Send] method | |||
<pre> | |||
irb(main):015:0> to = [:to_s , :to_f] | |||
=> [:to_s, :to_f] | |||
irb(main):016:0> to.each{|method| puts "#{method} => #{5.send method}"} | |||
to_s => 5 | |||
to_f => 5.0 | |||
=> [:to_s, :to_f] | |||
</pre> | |||
[http://ruby-doc.org/core-1.9.2/Object.html#method-i-respond_to-3F respond_to] method | |||
<pre> | |||
5.respond_to? :slice #=> false | |||
5.respond_to? :to_f #=> true | |||
</pre> | |||
<pre> | |||
obj = Object.new | |||
if obj.respond_to?(:program) | |||
obj.program | |||
else | |||
puts "Sorry, the object doesn't understand the 'program' message." | |||
end | |||
</pre> | |||
==method_missing== | |||
Whenever a call to a method is made on an object , Ruby does a method look up. If the method is not found, Ruby calls a method named '[http://ruby-doc.org/docs/ProgrammingRuby/html/ref_c_object.html#Object.method_missing method_missing]'. Ruby knows the existence of the 'method_missing' as all objects are instances of 'BasicObject' which includes 'method_missing'. The default behavior of BasicObject#method_missing is to respond by raising a [http://www.ruby-doc.org/core-1.9.2/NoMethodError.html NoMethodError]. | |||
[http://en.wikipedia.org/wiki/Method_overriding Overriding] 'method_missing' allows users to call methods that don't really exist. The example below illustrates overriding of 'method_missing' to the programmer's advantage. Ruby passes as parameters the name of the method called and the arguments passed to it. | |||
'''Example1''' | |||
<pre> | |||
class Cat | |||
def mew | |||
puts "Meow" | |||
end | |||
def method_missing(meth, *args) | |||
puts "Sorry, I do not #{meth}" | |||
end | |||
end | |||
c = Cat.new | |||
c.mew | |||
>>Meow | |||
c.bark | |||
>> Sorry, I do not bark | |||
</pre> | |||
In the above example, as the method 'bark' does not exist, method_missing is called with the meth (method name as a symbol) :bark. Hence the result " Sorry, I do not bark " | |||
'''Example2''' | |||
Using method_missing to convert Roman numerals <ref>http://www.rubyquiz.com/quiz22.html</ref> to integers | |||
<pre> | |||
class Roman | |||
DIGITS = { | |||
'I' => 1, | |||
'V' => 5, | |||
'X' => 10, | |||
'L' => 50, | |||
'C' => 100, | |||
'D' => 500, | |||
'M' => 1000, | |||
} | |||
def roman_to_integer(roman_string) | |||
last = nil | |||
roman_string.to_s.upcase.split(//).reverse.inject(0) do |memo, digit| | |||
if digit_value = DIGITS[digit] | |||
if last && last > digit_value | |||
memo -= digit_value | |||
else | |||
memo += digit_value | |||
end | |||
last = digit_value | |||
end | |||
memo | |||
end | |||
end | |||
def method_missing(method) | |||
str = method.id2name | |||
roman_to_integer(str) | |||
end | |||
end | |||
</pre> | |||
Evaluating Roman.xix calls the xix method of module Roman. Roman has no xix method, so method_missing is invoked with :xix as the argument.The id2name method of class Symbol is invoked on xix returning "xix". The "xix" is then parsed according to the rules for evaluating Roman numerals, and evaluates to 19. | |||
''' Example 3 ''' | |||
<pre> | |||
class Performer | |||
def method_missing(name, *args) | |||
"The duck will #{name}: #{args[0]}" | |||
end | |||
end | |||
duck = Performer.new | |||
duck.sing("Quacking in the Rain") # => "The duck will sing: Quacking in the Rain" | |||
duck.dance("Swan Lake") # => "The duck will dance: Swan Lake" | |||
</pre> | |||
==Applications of Reflection== | ==Applications of Reflection== | ||
*Reflection has become invaluable to programmers who need to connect code with data. For example in a GUI environment a button might need to invoke different methods in different classes. Reflection can be used here to call the method on any given class. | *Reflection has become invaluable to programmers who need to connect code with data. For example in a GUI environment a button might need to invoke different methods in different classes. Reflection can be used here to call the method on any given class. | ||
Line 54: | Line 232: | ||
*Reflection is very useful when the software is upgraded regularly. It provides an easy method to check for available methods and classes. This prevents the errors caused by the absense of methods and classes when they are deprecated. | *Reflection is very useful when the software is upgraded regularly. It provides an easy method to check for available methods and classes. This prevents the errors caused by the absense of methods and classes when they are deprecated. | ||
==Advantages and disadvantages of | ==Advantages and disadvantages of reflection== | ||
===Advantages=== | ===Advantages=== | ||
Line 61: | Line 239: | ||
* Debugging: Reflection allows the user to observe the private members in classes. This capability can be used to debug classes and their interactions. | * Debugging: Reflection allows the user to observe the private members in classes. This capability can be used to debug classes and their interactions. | ||
* Test Harness : Reflection can be used to call a set of testing APIs defined on a class for maximum coverage of testing. | * Test Harness : Reflection can be used to call a set of testing APIs defined on a class for maximum coverage of testing. | ||
* Correctness : Reflection improves the robustness and the correctness of a program especially in dynamically typed languages as runtime checks can be added to check the availability of the methods or classes. | |||
===Disadvantages=== | ===Disadvantages=== | ||
Line 66: | Line 245: | ||
* Since it provides access to the internals of a class or an encapsulated object security becomes a major issue. | * Since it provides access to the internals of a class or an encapsulated object security becomes a major issue. | ||
* Since it is run-time binding we lose the security of compile time checks and verification. | * Since it is run-time binding we lose the security of compile time checks and verification. | ||
==Conclusion== | |||
This article makes an attempt to explain the concept of Reflection in Object Oriented Programming. The article mentions the different approaches to reflection in Ruby and other languages.It mentions the usage of Reflections and the advantages and disadvantages of using Reflection. A follow up to this article would be to study the concept of [http://en.wikipedia.org/wiki/Metaprogramming Metaprogramming]. | |||
==References== | |||
<references/> | |||
==Additional Reading== | ==Additional Reading== | ||
*[http://en.wikipedia.org/wiki/Reflection_(computer_programming) Reflection] | |||
*[http://www.cs.indiana.edu/~jsobel/rop.html An Introduction to Reflection-Oriented Programming] | |||
*[http://tutorials.jenkov.com/java-reflection/classes.html Java Reflection] | |||
*[http://www.slideshare.net/CiaranMcHale/java-reflection-explained-simply Java reflection basics] | |||
*[http://www2.parc.com/csl/groups/sda/projects/reflection96/docs/malenfant/ref96/ref96.html A Tutorial on Behavioral Reflection and its Implementation] | |||
*[http://www.quora.com/Computer-Programming/How-is-reflection-useful Uses of reflection] | |||
*[http://download.oracle.com/javase/tutorial/reflect/index.html Java reflection official website] | |||
*[http://ruby-doc.org/docs/ProgrammingRuby/html/builtins.html Ruby Documentation] | |||
*[http://www.slideshare.net/MarcusDenker/behavioral-reflection Behavioral reflection] |
Latest revision as of 01:54, 30 October 2011
Introduction
Reflection is a relatively common computer programming concept where in the program has the inherent ability to examine itself at run time. Based on its observations the program can modify it's behavior for the given situation.The modifications can be any aspect of the programming language .i.e syntax, semantics, or implementation.
Reflection as a concept was first introduced in the doctoral dissertation of Dr. Brian Cantwell Smith<ref>Brian Cantwell Smith, Procedural Reflection in Programming Languages, Department of Electrical Engineering and Computer Science, Massachusetts Institute of Technology, PhD Thesis, 1982.</ref><ref>Brian C. Smith. Reflection and semantics in a procedural language. Technical Report MIT-LCS-TR-272, Massachusetts Institute of Technology, Cambridge, Mass., January 1982.</ref> in 1992.
Reflection
Reflection is the ability of a program or a computation to examine and modify itself at run time even though it does not have enough information at compile time. For example in a high level object oriented language the ability to inspect its class , interfaces and methods at run time without knowing their names at compile time. It provides the ability to modify , instantiate and access to methods such as getter's and setter's of a class. Since the program need not have all the information at compile time it makes the program more dynamic.
In the simple illustration provided below in ruby we can see how the name of a class can be obtained from the object and how we can get the ancestor classes and modules of a particular class.
5.class #=> Fixnum "hello".class #=> String String.ancestors #=> [String, Enumerable, Comparable, Object, Kernel]
Some of the common information that can be obtained from reflection are :
- Object type
- Super classes of any class
- Methods
- class fields
- Interfaces
Common languages that exhibit reflection to varying degrees are Ruby, Java, Smalltalk, C# and more.
Types of reflection
There are two basic types of reflection. They are:
- Behavioral Reflection: This type of reflection changes the behaviour of the execution of the program based on observation and modification.
- Structural Reflection: This type of reflection deals with changing the very structure of the program such as the data structures and flow of control in the program.
Implementation
There are many challenges faced by designers of reflective languages. They must provide as much leeway as possible for late binging and at the same time they must optimize the compilation of the static components so that they are ready for run-time. Reflection is in essense a connection between the object-level (program) and meta-level (the processor). The ability of the object level to be able to observe and modify the meta-level information is the consequence of this connection. These actions can be termed as introspection (This involves the action of observing the class) and intercession (this involves the operation of modifying the behavior of the class). These actions can implemented with the implementation of the following components:
- Ability to create first class objects ie reification.
- Ability to convert a string that denotes a class or a method into its corresponding reference or invocation.
- Ability to use and create symbolic links to methods and classes.
Reflection by example
C#
int val = 20; System.Type type = val.GetType(); System.Console.WriteLine(type);
Output is type of the variable "val" = System.Int32
Smalltalk
w := Workspace new. w openLabel:'My Workspace' w inspect
Here we can inspect all the methods available to the instance 'w'.
Java
import java.lang.reflect.*; public class Fclass{ public static void main(String[] args){ Class cls = java.lang.Integer.class; String info; info = cls.getName(); // It will show java.lang.Integer System.out.println(info); } }
cls.getName() gives the complete class name which is printed out as the output of the above code is "java.lang.Integer"
PHP
$reflector = new ReflectionClass("SimpleXMLElement"); echo $reflector;
Output of this example is the complete class map of the class SimpleXMLElement.
Dynamic binding : Making reflection possible
Ruby implements dynamic binding of objects. Dynamic binding plays a very important role in meta-programming.
In languages like C,C++; a simple assignment "a = b", would require 'a' and 'b' to be of the same type. The assignment is interpreted as copying b into a and is implemented by copying the contents of b into the space occupied by a. Thus if 'a' had been declared as an object whose memory size is less than b's object, then object slicing takes place i.e. only that part of 'b' which fits into a's memory would be copied. This behavior might lead to unintended consequences.
But dynamic binding in Ruby ensures that the type of object stored in a variable is determined at run time and not at compile time. Thus the assignment "a = b" is interpreted as binding 'a' to the same object that 'b' is bound to. It is implemented by copying the reference stored in b into the (pointer-sized) memory cell of 'a'. Thus 'a' and 'b' point to the same object after the assignment.
Symbols and their usage in reflection techniques
Basics
Symbols are objects used to represent names and strings inside a Ruby interpreter. They are immutable and remain unique i.e. every instance of a particular symbol is the same symbol.
Usage in reflection techniques
Symbols are widely used in reflection to invoke methods dynamically. Reflection methods like 'respond_to', 'send' make use of symbols as a reference to other methods. Strings can also be used in place of symbols. However symbols are more efficient compared to strings in terms of memory and performance.
Examples
Passing method by reference using a symbol
class Float def poly self*self*self + 2*self*self + 3*self + 4 end end
And we can pass poly to an integration routine:
area = integrate(:poly, 0, 10)
Symbols in reflection
Send method
irb(main):015:0> to = [:to_s , :to_f] => [:to_s, :to_f] irb(main):016:0> to.each{|method| puts "#{method} => #{5.send method}"} to_s => 5 to_f => 5.0 => [:to_s, :to_f]
respond_to method
5.respond_to? :slice #=> false 5.respond_to? :to_f #=> true
obj = Object.new if obj.respond_to?(:program) obj.program else puts "Sorry, the object doesn't understand the 'program' message." end
method_missing
Whenever a call to a method is made on an object , Ruby does a method look up. If the method is not found, Ruby calls a method named 'method_missing'. Ruby knows the existence of the 'method_missing' as all objects are instances of 'BasicObject' which includes 'method_missing'. The default behavior of BasicObject#method_missing is to respond by raising a NoMethodError.
Overriding 'method_missing' allows users to call methods that don't really exist. The example below illustrates overriding of 'method_missing' to the programmer's advantage. Ruby passes as parameters the name of the method called and the arguments passed to it.
Example1
class Cat def mew puts "Meow" end def method_missing(meth, *args) puts "Sorry, I do not #{meth}" end end c = Cat.new c.mew >>Meow c.bark >> Sorry, I do not bark
In the above example, as the method 'bark' does not exist, method_missing is called with the meth (method name as a symbol) :bark. Hence the result " Sorry, I do not bark "
Example2 Using method_missing to convert Roman numerals <ref>http://www.rubyquiz.com/quiz22.html</ref> to integers
class Roman DIGITS = { 'I' => 1, 'V' => 5, 'X' => 10, 'L' => 50, 'C' => 100, 'D' => 500, 'M' => 1000, } def roman_to_integer(roman_string) last = nil roman_string.to_s.upcase.split(//).reverse.inject(0) do |memo, digit| if digit_value = DIGITS[digit] if last && last > digit_value memo -= digit_value else memo += digit_value end last = digit_value end memo end end def method_missing(method) str = method.id2name roman_to_integer(str) end end
Evaluating Roman.xix calls the xix method of module Roman. Roman has no xix method, so method_missing is invoked with :xix as the argument.The id2name method of class Symbol is invoked on xix returning "xix". The "xix" is then parsed according to the rules for evaluating Roman numerals, and evaluates to 19.
Example 3
class Performer def method_missing(name, *args) "The duck will #{name}: #{args[0]}" end end duck = Performer.new duck.sing("Quacking in the Rain") # => "The duck will sing: Quacking in the Rain" duck.dance("Swan Lake") # => "The duck will dance: Swan Lake"
Applications of Reflection
- Reflection has become invaluable to programmers who need to connect code with data. For example in a GUI environment a button might need to invoke different methods in different classes. Reflection can be used here to call the method on any given class.
- Programmers who deal with a multitude of classes at the same time can use reflection to create a “serializer” that for a given class uses reflection to go through all the instance variables and processes them accordingly.
- Reflection is used in large test frameworks where reflection helps in identifying the test methods for different scenarios.
- Reflection provides the ability to morph the code based on dynamic situations. This provides a sense of artificial intelligence to the program as whole.
- Reflection can be used to debug and verify code as it provides access to the insides of a program.
- Reflection is very useful when the software is upgraded regularly. It provides an easy method to check for available methods and classes. This prevents the errors caused by the absense of methods and classes when they are deprecated.
Advantages and disadvantages of reflection
Advantages
- Extensibility: Reflection provides the capability of using external and user defined classes by instantiation of extensibility objects using their fully qualified names.
- Class browsers in IDEs: The ability to examine the members of classes makes implementation of visual aids , auto-completion and documentation easy in development tools for programmers.
- Debugging: Reflection allows the user to observe the private members in classes. This capability can be used to debug classes and their interactions.
- Test Harness : Reflection can be used to call a set of testing APIs defined on a class for maximum coverage of testing.
- Correctness : Reflection improves the robustness and the correctness of a program especially in dynamically typed languages as runtime checks can be added to check the availability of the methods or classes.
Disadvantages
- Reflection introduces lot of performance overhead when compared to non-reflective code. Hence it should be used judiciously.
- Since it provides access to the internals of a class or an encapsulated object security becomes a major issue.
- Since it is run-time binding we lose the security of compile time checks and verification.
Conclusion
This article makes an attempt to explain the concept of Reflection in Object Oriented Programming. The article mentions the different approaches to reflection in Ruby and other languages.It mentions the usage of Reflections and the advantages and disadvantages of using Reflection. A follow up to this article would be to study the concept of Metaprogramming.
References
<references/>