CSC/ECE 517 Fall 2009/wiki2 5 jn
Reflection APIs (TOC)
Introduction
What is Reflection?
Reflection in programming is a technique in which programs are able to dynamically view and alter their own structure and flow. For example, in reflection one could determine method/variable/class names, add or delete method/variables, alter code to current methods, or simply alter values in variables. Reflection is a subset of MetaProgramming which relies heavily on the use of meta-information. Meta-Information is used to keep track of the program structure such as names of available methods,variables and classes but also is what really makes reflection possible. In theory there are nearly no bounds to reflection as it directly modifies the binary of the program. The current limitations of this process are related to the APIs avaliable for specific languages. Majority of object-oriented languages have the functionality built in and some like C++ require external libraries to achieve even the basic functionality of Reflection.
What languages are Supported?
Due to the complexity required to support this majority of the languages that support this feature tend to be object oriented. Some examples of supported languages are Java, Ruby, C#, Perl, PHP, JavaScript, Python, and ActionScript. In this page we will cover a select few of the languages above and what native API support is avaliable for each of the languages.
Terminology
- Reflection
- MetaProgramming
- Binding
- Instance
- Scope
Available Reflection APIs
Reflection in C#
Reflection in Java
Reflection in Ruby
The nature of Ruby as an object-oriented language gives great support for Reflection. The current support for reflection in ruby is built into the language and is accessable through certain fuctions within the standard Ruby API. The methods most commonly used for reflection in Ruby along with some basic examples of their usage are shown below.
Eval Method
The eval method is defined in the Kernel Module of Ruby and is used to evaluate literals encompased in strings. This may not seem useful but the eval method also work in the scope of bindings which represent the scope of execution at a particular place in the code. This allows programmers to view any variables in any scope for any instance. An example of eval's usage is shown below.
Example
class Test def initialize(var) @secret = n end def getBinding return binding() end end test1 = Test.new("12+5") #We can determine what test1's instance of secret is and evaluate it without an accessor method eval("@secret", test1.getBinding) #=> 17
I this example we can see that by acquiring the binding at some scope in the program we can use it to get inside the context of any object instance and determine the value of any instance variables.
Instance Eval Method
The instance_eval method is defined in the Object class and works within the instance of any class. This method performs much of the same operations as the eval method but works in the scope of an object without requiring the binding statement as above. In fact we can accomplish the same example as above with the code shown below.
Example
class Test def initialize(var) @secret = n end end test1 = Test.new("12+5") #We can determine what test1's instance of secret is and evaluate it without an accessor method test1.instance_eval { @secret } #=> 17
Again this code performs exactly the same thing as the prior example above. The result is 17 which is the evaluation of the string literal as a command.
Class Eval Method
The class_eval method is defined in the Module class and works within the instance of any class. This method can be used to work within the context of any object whether that is assigning or accessing variables, declaring instance methods, or even re-defining inherited methods. The method takes actions either via string literal or a block of code. This method is one of the strongest and most versatile methods in the Ruby Reflection API since it can access any private methods of any objects and its parents, this giving you full control over control.
Example 1
class Test def initialize(var) @secret = n end end test1 = Test.new("12+5") #We can determine what test1's instance of secret by creating an accessor method for this instance. test1.class_eval{ def getSecret; @secret; end } eval(test1.getSecret) #=> 17 #Or by simply accessing the local variable as below. eval(test1.class_eval{@secret}) #=> 17
This example shows the versatility of the class_eval method to work on any class instance. It performs many of the operations that the previous methods have performed but with the added advantage of assigning instance methods.
Example 2
class Test def initialize(var) @secret = n end private: def increment @secret += 1 end end test1 = Test.new(17) #We can directly use class_eval to call private methods within a class as well. test1.class_eval{ increment() } #=> 18
This example shows that class_eval has even more flexibility to call private functions of a class from outside of the class scope.
Example 3
class Test def initialize(var) @secret = n end end test1 = Test.new(17) # We can directly use class_eval to add variables to the instance of the class test1.class_eval{ instance_variable_set :@secret2 , 25 } test1.class_eval{ @secret2 } #=> 25 # Or We can remove variables from an instance of the class test1.class_eval{ remove_instance_variable :@secret2 } test1.class_eval{ @secret2 } #=> nil
This example shows that class_eval is capable of defining and removing instance variables from the instance of a class.
Define Method Method
The define_method method is defined in the Module class and works within the instance of any class. This method can be used to work within the context of any object to declare methods directly. This method can be accomplished by using the class_eval method but is also a bit more flexible in it's notation. An example of the use of this function is shown below.
Example
class Test def initialize(var) @secret = n end end test1 = Test.new("This is my String!") #We can use define_method to create a instance method for this class with multiple parameters. test1.class_eval{ define_method(:getSubString){|start, end| @secret[start,end]} } test1.getSubString(5,9) #=> "is my"
This example shows how to use define_method to create an instance method with multiple parameters by the common block notation. Please not that we did have to use class_eval still to access the define_method. This was due to the fact that define_method is a private method within the Module class.
Conclusion
The ruby language provides great support for reflection due to the nature of its design. By using the class_eval method by itself one could completely encompass majority of the required reflection programming. The other functions do provide some other basic support not specifically granted to the class_eval function. Specifically the eval function in combination with bindings. The use of bindings allow the program to save the context of scope at some particular moment in the program and access it later. With these functions ruby makes reflection simple.
Reflection in PHP
Reflection in PERL
Reflection in ActionScript
Conclusions
Links
[2] Reflection in C# - CoderSource.net
[3]