CSC/ECE 517 Fall 2012/ch1b 1w40 as

From Expertiza_Wiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

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. Precisely, "Reflection" can be defined as a language's ability to inspect and dynamically call classes, methods, attributes, etc. at runtime. More advanced uses of reflection let you list and call methods, constructors, etc.

Reflection is important since it lets you write programs that does not have to "know" everything at compile time, making them more dynamic, since they can be tied together at runtime. 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. The code can be written against known interfaces, but the actual classes to be used can be instantiated using reflection from configuration files. Lots of modern frameworks uses reflection extensively for this very reason. In scripting languages like Python reflection is even more tightly integrated, since it matches more naturally with the general programming model.

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.

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.


7.class #=> Fixnum

"helloworld".class #=> String

String.ancestors #=> [String, Enumerable, Comparable, Object, Kernel]

Some of the common information that can be obtained from reflection are :

These are discussed in detail in the below sections. Common languages that exhibit reflection to varying degrees are Ruby, Java, Smalltalk, C# and more.

There are two basic types of reflection:

  • 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 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 in C#

Features

In C#, Reflection uses the type system. C# is a strongly-typed language in which every variable and constant has a type. Not only this, but every expression that evaluates to a value is also associated with a type. Every method signature specifies a type for each input parameter and for the return value. A typical C# program uses the types from the class library as an addition to the user-defined types that are specific to the program's problem domain.

C# maintains a special database called the ‘metadata’ where a compiled C# program is usually encoded and stored. This metadata can then be used by reflection to act upon and read the required data present in it. This provides astonishing features such as accessing the members of an object or class based on their string names. This can be done by using the System.Reflection namespace provided in C#.

As an example, the below program uses the System.Reflection namespace to access the metadata of itself. It searches for the public field with the name "_mynumber" and then acquires its value.

using System;
using System.Reflection;

class ReflectionUsage
{
   public static int _mynumber = 4;
   static void Main()
   {
    Type type = typeof(ReflectionUsage);
    FieldInfo info = type.GetField("_mynumber");
    object obj = type.GetValue(null);
    Console.WriteLine(obj);
   }
}

This program would then output the number ‘4’ which is the value that is assigned to the variable “_mynumber”.

Here is how the System.Reflection class contains in C#.

Below are the several powerful reflection features that are provided by C#:

Field Reflection: This gives the power to scan or search the fields in your C# program by using the GetField or GetFields methods. Using this reflection we can load field values and then loop through those fields and display their names and values. The System.Reflection namespace provides a powerful and maintainable way to enumerate fields and properties. It can then access these fields by name.

SetValue Reflection: SetValue accesses the fields by their names. We can take a string that usually represents a target field, and then using the System.Reflection namespace methods, change the actual value of that field. Below is an example that does precisely this:

using System;
using System.Reflection;
class ReflectionUsage
{
   public static int _myfield;
   static void Main()
   {
    FieldInfo info = typeof(ReflectionUsage).GetField("_myfield");
    info.SetValue(null, 2012);
    Console.WriteLine(_myfield);
   }
}

The above program would output 2012 which is the value that we set using the SetValue reflection.

MethodInfo Invoke: Let us say we have the name of a method in the string format and want to invoke it. In such a case, one can use the GetMethod method and then invoke the MethodInfo that can be acquired from it. The invoke method can be called to invoke method with the name specified by the string.

Type Reflection: Type is one of the most important types when using reflection in C#. The Type type is used to describe data types. It stores the C# type information in a variable, property or field and can be used as an argument.

Sizeof: The sizeof operator exposes information about the implementation of types in the code. It does not require the System.Reflection namespace. However, it is related to reflection in the sense that it expresses information about the program itself.

Advantages:

1. In C#, one can write code that uses for example a System.Xml.XMLDataDocument class, which loads and parses an XML document and then allows you to parse the DOM during runtime. During parsing, every time that an <object> node is scanned, a new object needs to be created using its FQN (fully qualified name). Every time a <property> node is parsed, then its parent node's property needs to be set to a newly created object. Also, every time that a <function> node is parsed, the parent object that is created must have the function, by name, called on it using the arguments that are later defined. This would allow you to create any object type that you want, and set properties and call functions for initialization, in a very recursive manner. The use of reflection would render this code to be surprisingly small because it takes advantage of recursion and the generic nature of reflection.

2. Programs that use reflection have the ability to look inside themselves to see their own inner workings and structure. This capacity can lend them unique and powerful features that can be used to write better code.

Disadvantages:

1. One main disadvantage of using reflection would be that reflection in general is that they can render programs that are less clear to read, harder to understand. A new person reading the code can find it hard to grasp what the code is actually doing.

2. Another disadvantage is that it can render programs that are generally slower.

Reflection in Java

Reflection is a part of Java API which enables Java code to inspect and reflect Java components like class and objects during runtime. Classes in the java.lang.reflect package along with java.lang.Class and java.lang.Package take care of applications like degugger, interpreters, objects inspectors, class browsers. Important protocols such as SOAP and JavaBeans would not have been possible, if it weren't for Reflection. The aid a developer gets from an IDE (Integrated Development Environment) during coding is achieved by using nothing else but Reflection. Reflection is one of the advanced features of Java, it gives runtime information about the objects, classes, fields and methods in a class, interfaces, etc. The image below shows some major functions related to java reflection.

Now we will have a look at some of the important features in Java Reflection and will see how they are implemented.

Features

Classes: The first thing any programmer would do using reflection would be to inspect Java classes at runtime. The java package java.lang.Class helps to gather all important information about the class at runtime. We can obtain class name, class modifiers, constructors, field, method, superclass, implemented interface etc.

Before you can do any inspection on a class you need to obtain its java.lang.Class object. All types in Java including the primitive types (int, long, float etc.) including arrays have an associated Class object. If you know the name of the class at compile time you can obtain a Class object like this: Code:

public class DemoClass{
public static void main(String[] args)
{
Class obtainClass = DemoClass.class;
String className = obtainClass.getName();
 System.out.printf("ClassName: %s\n",className);
}
}

Constructors:

Using Java reflection one can inspect the constructors of classes and instantiate object of that class at runtime. This is done using Java class java.lang.reflect.Constructor. The steps to do this operation are as follows: 1) obtaining constructor objects 2) get constructor parameters 3) Instantiating Objects using constructors

 
import java.lang.reflect.*;
public class DemoClass{

public String msg;

public DemoClass(String forMsg){
msg = forMsg;
}

public static void main(String[] args)
{
try{
Class obtainClass = DemoClass.class;
Constructor constructor = obtainClass.getConstructor(new Class[]{String.class});
DemoClass myDemo = (DemoClass)constructor.newInstance("Welcome to Java Reflection");
System.out.printf("New Instance String: %s\n",myDemo.msg);

}
catch(Exception e)
{
System.err.printf(e.getMessage());
}
}
}

Field: Inspecting the fields of classes and get/set them at runtime is another feature provided by Java Reflection. This is done using Java class java.lang.reflect.Field. To get/set a field value using Java reflection following are steps involved: obtaining field objects, field name, field type and getting and setting field values. eg:

Class objClass = MyObject.class;
Field[] methods = objClass.getFields();

Methods: One can also inspect the methods of class at runtime and invoke them. The class to implement this functionality is java.lang.reflect.Method. The steps to obtain methods from a class are: Obtaining Method Objects Method Parameters and Return Types Invoking Methods using Method object.


For eg:

Class objClass = MyObject.class;
Field[] methods = objClass.getMethods();

Advantages

1) One of the major advantage of Java reflection is in debugging. While debugging one should be able to examine the private members of classes. 2) Also while testing one should be able to enlist all members of class along with the relationship with superclass so as to ensure that all code branches are covered.

Disadvantages

1) Java reflection provides access to private variables and methods, this exposes the implementation of the class. Such use of class functionalities which break the abstraction can result is portability problems in future upgrades.

2) Reflection involves method execution which resolve at runtime, so with certain Java virtual machines which do not perform optimizations can result in performance overhead with use to Java reflection.

Reflection in Ruby

Ruby is a dynamic language and one of many advantages which Ruby provides is its ability to introspect into a class or object known as reflection. What kind of introspection Ruby provides? It provides a way to inspect class objects using instance_of?, class hierarchy using ancestors, contents & behavior of class like which operations it supports, instance variables, etc and information on methods.

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.

Feature Comparison

Ruby provides a very good reflection ability where one can introspect various properties about an object and the class it belongs to, during runtime. One can obtain the list of methods that are supported on an object by using the 'methods' reflection method on the object. In addition, the 'class' reflection method enables one to query the class that an object belongs to. Similarly, the 'superclass' method allows one to inspect all the super classes of the class that an object belongs to.

In PHP, we have a class called as ReflectionClass which holds the class type for a particlar class. In the class row for PHP we can see that all Reflection operations can be performed on only class Reflection. So as to check if a particular instance belongs to class 'Foo', we need to first create the ReflectionClass object as shown and then call isInstance(argument) method on it. PHP also has getMethods() method which returns a list of class methods.

In Objective C, every type we see is of type class, whether it be String, Integer or Double. So type check in Objective C can be done using method isKindOfClass. But to perform other Reflection tasks, one needs to obtain the object of class first using the object_getClass(Class_Object) method. Once this object is obtained we can then perform operations like getting method list, etc as shown in table.

Ruby PHP Objective C
Class Method: instance_of?
obj.instance_of? String
Method: isInstance()
<?php
$class = new ReflectionClass('Foo');
if ($class->isInstance($arg)) {
   echo "Yes";
}
?>
Method: isKindOfClass
if([myObject isKindOfClass:[MyObject class])
{
//do something
}
Method Method: methods
 list = r.methods 
Method: ReflectionClass::getMethods
 $class = new ReflectionClass('Apple');
$methods = $class->getMethods();
Method: class_copyMethodList()
SomeClass * t = [[SomeClass alloc] init];
unsigned int mc = 0;
Method * mlist = 
class_copyMethodList
(object_getClass(t), &mc);
Type Method: Object.class
 "Hello".class
>>String
Method: gettype()
<?php
$data = array(1, 'foo');
foreach ($data as $value) {
    echo gettype($value), "\n";
}?>
Method: isKindOfClass
if([myDemo isKindOfClass:[DemoClass class]])
{
    //code
}
String representation of an object Method: to_s
obj.to_s 
Method: ReflectionClass::__toString —
<?php
$reflectionClass = 
new ReflectionClass(MyDemoClass);
echo $reflectionClass->__toString();
?>
Method: [NSString stringWithFormat:""]
*objString = [NSString 
stringWithFormat:”%@”,myObject]

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 and Test Harness: Reflection allows the user to observe the private members in classes. This capability can be used to debug classes and their interactions. 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

  • Performance Overhead: Reflection resolves types of objects and classes are dynamically at runtime, this introduces lot of performance overhead when compared to non-reflective code. Hence it should be used judiciously.
  • Security: At run-time binding in reflection we loose the security of compile time checks and verification. It also provides access to the internals of a class or an encapsulated object like private methods and variables which makes security a major issue.
  • Portability: Another issue is of portability, over a period of time the code may change during updates and a Reflective code breaks abstraction. Such a code may change behavior during updates and may become dysfunctional.

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/>

Additional Reading