CSC/ECE 517 Fall 2011/ch4 4f ss: Difference between revisions
(56 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
==Introduction == | |||
Here we mainly focus on the lecture 11 of CSC 517 which is Reflection in Ruby. Some of the the examples used are the same as mentioned in the class notes and are elaborated in more detail. We also cover additional information on Reflection in Java,its applications and the advantages and disadvantages of Reflection in general. | |||
== Reflection == | == Reflection == | ||
[http://en.wikipedia.org/wiki/Reflection_(computer_programming) Reflection] allows program entities to discover things about themselves through introspection. | [http://en.wikipedia.org/wiki/Reflection_(computer_programming) Reflection] allows program entities to discover things about themselves through introspection. | ||
In other words,Reflection is the ability of a program to determine information about an object at runtime. | In other words,Reflection is the ability of a program to determine information about an object at [http://en.wikipedia.org/wiki/Run_time_(program_lifecycle_phase) runtime]. | ||
The information may include the following : | The information may include the following : | ||
Line 11: | Line 15: | ||
* Names and types of the [http://en.wikipedia.org/wiki/Attribute_(computer_science) attributes] of the object. | * Names and types of the [http://en.wikipedia.org/wiki/Attribute_(computer_science) attributes] of the object. | ||
Reflection is supported by many [http://en.wikipedia.org/wiki/Object-oriented_programming Object-oriented programming]languages in various forms. Powerful and flexible reflection mechanisms are exhibited by | Reflection is supported by many [http://en.wikipedia.org/wiki/Object-oriented_programming Object-oriented programming]languages in various forms. Powerful and flexible reflection mechanisms are exhibited by [http://www.smalltalk.org/main/ Smalltalk], [http://en.wikipedia.org/wiki/Ruby_(programming_language) Ruby] and [http://www.python.org/ Python]. [http://en.wikipedia.org/wiki/Java_%28programming_language%29 Java] also supports reflection. But reflection in java is verbose and is not as flexible and dynamic as these languages. [http://www.cplusplus.com/doc/tutorial/ C++] allows a program to determine the type of an object at run-time. Thus it does support reflection but in a limited form only. [http://en.wikipedia.org/wiki/Eiffel_(programming_language) Eiffel] also has support for a limited form of reflection which includes the ability to determine the features contained in an object. | ||
== Reflection in Ruby == | == Reflection in Ruby == | ||
In Ruby, reflection is simpler because it is done using the language mechanisms ie .methods gives the list of methods. | In Ruby, reflection is simpler because it is done using the language mechanisms ie <object>''.methods'' gives the list of methods. This is in contrast to reflection in java which is much more verbose because we need to use class names,method names,parameter names etc. | ||
===Examples of Reflection in Ruby=== | ===Examples of Reflection in Ruby=== | ||
Line 36: | Line 40: | ||
:object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exe | :object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exe | ||
c, :__send__] | c, :__send__] | ||
</pre> This is an example of discovering things about 3.1459 at runtime.(Reflection). | </pre> This is an example of discovering things about 3.1459 at runtime.(Reflection).Using Reflection,we can act on information during runtime without compiling it in. Information needed can be found out at run-time instead of writing code at compile time. | ||
'''Example:''' | |||
<pre>puts "hello".class #returns the class of object "hello" | <pre>puts "hello".class #returns the class of object "hello" | ||
Output: | Output: | ||
String</pre> | =>String</pre> | ||
'''Example:''' | |||
<pre>puts "hello".class.superclass #returns the superclass of the String class | <pre>puts "hello".class.superclass #returns the superclass of the String class | ||
Output: | Output: | ||
Object</pre> | =>Object</pre> | ||
'''Example:''' | |||
<pre> | |||
puts 100.class # print the class of 100 | |||
>> Fixnum | |||
puts 98343098452405890454.class #prints the class of 98343098452405890454 | |||
>> Bignum | |||
puts 123456789012345.kind_of? Integer # | |||
>> true | |||
puts 123456789012345.instance_of? Integer # | |||
>> false | |||
puts 123456789012345.instance_of? Bignum | |||
>> true | |||
#instance_of? is a method of Object.returns true if the object is an instance of the #given class | |||
</pre> | |||
'''Difference between Fixnum and Bignum in Ruby''' | |||
A [http://ruby-doc.org/core-1.9.2/Fixnum.html Fixnum] stores Integer values which can be represented in a native machine word (minus 1 bit). If an operation on a Fixnum results in a value that exceeds the range, the value is automatically converted to a Bignum. | |||
When Fixnum objects are assigned or passed as parameters, the actual objects are passed, rather than references to the objects. There is only one Fixnum object instance for a given integer value | |||
[http://ruby-doc.org/core-1.9.2/Bignum.html Bignum] objects are used to store values of integers outside the range of Fixnum. They are created automatically when encountered with integer calculations that would overflow a Fixnum. When a calculation involving Bignum objects returns a result that will fit in a Fixnum, the result is automatically converted. | |||
OO Languages distinguish between a [http://en.wikipedia.org/wiki/Primitive_data_type primitive] and [http://en.wikipedia.org/wiki/Reference_type reference]with help of a leading or trailing bit. ie One bit indicates if the remaining bits store a primitive or a reference and the remaining bits represent the value. In numeric calculations, most of numbers are primitives so primitives can be used directly avoiding the overhead of indirection. One main difference between Fixnum and Bignum is that Fixnum can be stored in 1 machine word. If the object cannot be stored in a machine word then Bignum is used. In case of Bignum a reference to the actual object is stored.In contrast to Fixnum objects, objects references to objects are used for parameter passing. | |||
Example | '''Example:''' | ||
<pre>puts string.ancestors #returns the ancestors of the string class | <pre>puts string.ancestors #returns the ancestors of the string class | ||
Line 61: | Line 95: | ||
</pre> | </pre> | ||
Comparable which is an ancestor of the String class is a mixin.It is used to provide the comparable functionality (operations like <,>,<=,>= etc)to the String class based on the definition of the rocket method. | [http://ruby-doc.org/core-1.9.2/Comparable.html '''Comparable'''] which is an ancestor of the [http://ruby-doc.org/core-1.9.2/String.html String] class is a [http://en.wikipedia.org/wiki/Mixin mixin] .It is used to provide the comparable functionality (operations like <,>,<=,>= etc)to the String class based on the definition of the rocket method. | ||
Object is the superclass of all classes.Its methods are available to all classes unless explicitly overridden. It provides methods like to_s,eql? etc. | [http://ruby-doc.org/core-1.9.2/Object.html '''Object'''] is the superclass of all classes.Its methods are available to all classes unless explicitly overridden. It provides methods like to_s,eql? etc. | ||
Basic Object is the parent class of all classes in ruby including Object class. It is an explicit blank class. | [http://ruby-doc.org/core-1.9.2/BasicObject.html '''Basic Object'''] is the parent class of all classes in ruby including Object class. It is an explicit blank class. | ||
Kernel is a module is included by class Object(hence a mixin). Its methods are available in all Ruby objects. | [http://ruby-doc.org/core-1.9.2/Kernel.html '''Kernel'''] is a [http://www.rubyist.net/~slagell/ruby/modules.html module] is included by class Object(hence a mixin). Its methods are available in all Ruby objects. | ||
<pre> | <pre> | ||
Line 74: | Line 108: | ||
</pre> | </pre> | ||
Integer is the basic for Fixnum and Bignum which are two concrete classes that hold whole numbers in ruby. | [http://ruby-doc.org/core-1.9.2/Integer.html '''Integer''']is the basic for Fixnum and Bignum which are two concrete classes that hold whole numbers in ruby. | ||
Numeric is a class which is used to provide methods like abs,floor,ceil,modulo,unary +,unary - etc. ie methods which can be performed on numbers in general. | [http://ruby-doc.org/core-1.9.2/Numeric.html '''Numeric'''] is a class which is used to provide methods like abs,floor,ceil,modulo,unary +,unary - etc. ie methods which can be performed on numbers in general. | ||
Comparable which is an ancestor of the Fixnum class is a mixin.It is used to provide the comparable functionality (operations like <,>,<=,>= etc)to the FixNum class based on the definition of the rocket method. | '''Comparable''' which is an ancestor of the Fixnum class is a mixin.It is used to provide the comparable functionality (operations like <,>,<=,>= etc)to the FixNum class based on the definition of the rocket method. | ||
We have discussed the Object and BasicObject classes in the above example | We have discussed the Object and BasicObject classes in the above example. | ||
Note: It is useful to print out the name of a class while debugging.A class of an object should not be tested while debugging in objected oriented programming. It is advised to use polymorphism to replace code that tests the class of an object and performs certain things. | '''Note''': It is useful to print out the name of a class while [http://searchsoftwarequality.techtarget.com/definition/debugging debugging]. A class of an object should not be tested while debugging in objected oriented programming. It is advised to use polymorphism to replace code that tests the class of an object and performs certain things. | ||
'''Example:''' | |||
<pre> if s.kind_of? Integer then this_method else that_method end | |||
#this is not a good practice.Should be replaced by [http://en.wikipedia.org/wiki/Polymorphism_(computer_science) polymorphism]. | |||
</pre> | |||
'''Assignment''' | '''Assignment''' | ||
In some languages like C, C++, or Ada, an assignment statement like x = y is interpreted as copying the contents of variable y into the variable x. It is generally required that x,y should be of the same type and size. But it is allowed in certain cases when the variables are of similar types.In C++, if the sizes are different say ,size of x is less than the size of y there will be a loss of data during assignment.(Slicing). | |||
Thus in | Ruby exhibits [http://en.wikipedia.org/wiki/Dynamic_binding_(computer_science) dynamic binding], not [http://geekexplains.blogspot.com/2008/06/dynamic-binding-vs-static-binding-in.html static binding] ie the type of the object in a variable is determined at runtime but not at compile time. | ||
Therefore in Ruby, x = y can be 'interpreted as bind x to the same object that y is bound to'. The assignment operation is implemented by copying the reference stored in y into x. | |||
Thus in Ruby,assignments physically copy references, but not the objects. | |||
===Obtaining Reference to a method in Ruby=== | ===Obtaining Reference to a method in Ruby=== | ||
A reference to a method can be obtained by using the method ''method'' in the class ''Object''. | A reference to a method can be obtained by using the method ''method'' in the class ''Object''. | ||
It is available to all classes, since Object is the | It is available to all classes, since Object is the super class of all classes. The reference thus obtained can be used to invoke that particular method. | ||
'''Example:''' | |||
<pre> | <pre> | ||
str = "Hello, World" | str = "Hello, World" | ||
#The name of the method has to be passed as a | #The name of the method(as a symbol) has to be passed as a parameter to 'method' | ||
m = str.method(:upcase) # returns a Method object which is a closure. | m = str.method(:upcase) # returns a Method object which is a closure. | ||
puts m.call #returns "HELLO,WORLD" | puts m.call #returns "HELLO,WORLD" | ||
</pre> | </pre> | ||
In the above example,a reference to the method upcase of the String class is obtained by passing the [http://www.troubleshooters.com/codecorn/ruby/symbols.htm symbol]:upcase to the 'method' method of the String class. The reference(m) can then be used to invoke the method 'upcase' on the string object. | |||
Note that in the above example name of the method passed as a symbol.This is because symbols are immutable and every instance of a particular symbol is the same symbol .In contrast,every instance of a particular string is a different string and hence has a different object id as seen in the example below. | Note that in the above example name of the method passed as a symbol.This is because symbols are immutable and every instance of a particular symbol is the same symbol. Thus symbols cannot appear in the left side of an assigment.In contrast,every instance of a particular string is a different string and hence has a different object id as seen in the example below. | ||
'''Example:''' | |||
<pre> | <pre> | ||
irb(main):009:0> puts :mysymbol.object_id | irb(main):009:0> puts :mysymbol.object_id | ||
332648 | 332648 | ||
=> nil | => nil | ||
irb(main):010:0> puts :mysymbol.object_id #Note that 2 occurrences of the same symbol | irb(main):010:0> puts :mysymbol.object_id #Note that 2 occurrences of the same symbol | ||
332648 #same object id unlike strings (shown next) | 332648 # yielded same object id unlike strings (shown next) | ||
=> nil | => nil | ||
irb(main):011:0> puts "mystring".object_id | irb(main):011:0> puts "mystring".object_id | ||
Line 124: | Line 164: | ||
===Applications of passing methods as parameters=== | ===Applications of passing methods as parameters=== | ||
'''Quadrature integration''' | [http://en.wikipedia.org/wiki/Numerical_integration'''Quadrature integration'''] | ||
Here we compute the area under a curve say f(x) between two points say 'a' and 'b' by dividing the region under the curve into 'n' small rectangles with the heights parallel to the y axis.ie The length a to b is divided into n intervals.The area of each rectangle can be obtained by multiplying the height and the width.Height is the average of the values of f(x) at the two end points of the interval.Width is the length of the interval . Sum of the areas of all the rectangles gives us an approximation of the area of the area under f(x). | |||
Suppose we need to compute the area under a curve described by some function, | '''Example:''' Suppose we need to compute the area under a curve described by some function, x2 + 2x + 3 between say 10 and 20. | ||
Then we can define a method poly for the Float class which returns the evaluation of the polynomial at that point. | |||
<pre> | |||
class Float | class Float | ||
def poly | def poly | ||
self*self + 2*self + 3 | self*self + 2*self + 3 | ||
end | end | ||
end | |||
</pre> | |||
And to compute the area,we pass poly to an integration method which takes the method reference, | And to compute the area,we pass poly to an integration method which takes the method reference,end points between which the area is to be computed as the parameters | ||
area = integrate(:poly, 10, 20) #calculates the area of the curve x2+2x+3 between the | <pre>area = integrate(:poly, 10, 20) #calculates the area of the curve x2+2x+3 between the #points x=10 to x=20. | ||
</pre> | |||
===Intercepting calls to undefined methods=== | ===Intercepting calls to undefined methods=== | ||
Ruby provides an option to intercept the call when a call to an undefined method is made on an object. | Ruby provides an option to intercept the call when a call to an undefined method is made on an object. | ||
Implementation of the method method_missing within the class definition provides this facility. Ruby passes | Implementation of the method [http://ruby-doc.org/docs/ProgrammingRuby/html/ref_c_object.html#Object.method_missing method_missing]within the class definition provides this facility. This feature is not available in java. A class cast [http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Exception.html exception] is thrown whenever a call to an undefined method is made. Ruby passes the name of the method called(which is unavailable) and the arguments passed to it as parameters to the method_missing method. | ||
'''Example:''' In the following example, class Duck defines 'quack' and 'method_missing' methods. When an object d of Duck is created and quack is invoked on it,it executes the quack of Duck(as expected). But when 'bark' is invoked on it, method_missing is invoked. | |||
<pre> | |||
class Duck | class Duck | ||
def quack | def quack | ||
puts "Quack" | puts "Quack" | ||
end | end | ||
def method_missing(meth, *args) | def method_missing(meth, *args) #handles calls to undefined methods | ||
puts "Sorry, I do not #{meth}" | puts "Sorry, I do not #{meth}" | ||
end | end | ||
end | end | ||
d = Duck.new | d = Duck.new | ||
d.quack | d.quack | ||
>>Quack | >>Quack | ||
d.bark | d.bark #bark is passed to method_missing since 'bark' method is not defined in Duck class. | ||
>> Sorry, I do not bark | >> Sorry, I do not bark | ||
</pre> | |||
Example of an interesting usage of method_missing: “Roman method_missing”. | '''Example of an interesting usage of method_missing: “Roman method_missing”.''' | ||
<pre> | <pre> | ||
class Roman | |||
=== | DIGITS = { | ||
'I' => 1, | |||
'V' => 5, | |||
'X' => 10, | |||
'L' => 50, | |||
'C' => 100, | |||
'D' => 500, | |||
'M' => 1000, | |||
} | |||
def roman_to_integer(roman_string) | |||
prev = nil #prev stores the previous value in roman string | |||
roman_string.to_s.upcase.split(//).reverse.inject(0) do |memo, digit| | |||
if digit_value = DIGITS[digit] #checks if the integer value is present in the hash | |||
if prev && prev > digit_value | |||
memo -= digit_value | |||
else | |||
memo += digit_value | |||
end | |||
prev = digit_value | |||
end | |||
memo | |||
end | |||
end | |||
def method_missing(method) | |||
str = method.id2name | |||
roman_to_integer(str) | |||
end | |||
end | |||
r=Roman.new | |||
r.XV | |||
Output : =>15 | |||
</pre> | |||
In | In this example we declare a class Roman containing a [http://programmingbulls.com/ruby-hash hash] called DIGITS which maps Roman symbols with the corresponding integers. The class also contains the methods method_missing and roman_to_integer. When an object of Roman class( say r) is created and when we invoke method XV on r (ie r.XV) ,method_missing(:XV) is invoked since the Roman class has no method named XV. Inside method_missing, the symbol is converted to "XV"(string) and roman_to_str("XV") is called. In roman_to_str method, the string is converted to uppercase, split into an array and the array is reversed. The inject operator then passes each element (of the array) and an accumulator value (memo)to the block.The initial value of memo is 0. For each element,if the previous digit_value exists and is greater than the current digit_value,the current digit_value is added to memo. Else current digit_value is subtracted from memo.The result becomes the new value for memo. At the end of the iteration, the final value of memo is the integer value of the Roman string. | ||
==Reflection in Java== | |||
== Reflection in Java == | |||
Reflection in Java is much more verbose than in ruby.It is an advanced feature of the Java environment. Reflection is achieved using the Reflection API.The verbosity of reflection in java may be associated with the usage of the library for reflection. | Reflection in Java is much more verbose than in ruby.It is an advanced feature of the Java environment. Reflection is achieved using the Reflection API.The verbosity of reflection in java may be associated with the usage of the library for reflection. | ||
Reflection is an advanced feature of the Java environment. It gives runtime information about objects, classes, and interfaces. Some of the questions that can be answered using reflection in java: | Reflection is an advanced feature of the Java environment. It gives runtime information about objects, classes, and interfaces. Some of the questions that can be answered using reflection in java: | ||
* Which [http://en.wikipedia.org/wiki/Class_%28computer_science%29 class] does an [http://download.oracle.com/javase/tutorial/java/concepts/object.html object] belong to? | |||
* What is the description of a given class name? | |||
* What are the fields in a given class? | |||
* What is the type of a field? | |||
* What are the methods in a class? | |||
* What are the parameters of a method? | |||
* What are the constructors of a given class? | |||
* Constructing an object using a given [http://www.leepoint.net/notes-java/oop/constructors/constructor.html constructor] | |||
* Invoking an object's method using such-and-such parameters. | |||
* Assigning a value to an object's field. | |||
* Dynamically creating and manipulating arrays. | |||
'''Java Reflection Classes''' | '''Java Reflection Classes''' | ||
All Reflection classes (With the exception of the class Class that resides in the default Java package) are contained in the package java.lang.reflect. | All Reflection classes (With the exception of the class Class that resides in the default Java package) are contained in the package [http://download.oracle.com/javase/1.4.2/docs/api/java/lang/reflect/package-summary.html java.lang.reflect]. | ||
Following are some of the classes used to various represent members of a class.: | Following are some of the classes used to various represent members of a class.: | ||
Classes-'Class' | |||
* Classes-[http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Class.html 'Class'] | |||
* Class Fields-[http://download.oracle.com/javase/1.4.2/docs/api/java/lang/reflect/Field.html 'Field Class'] | |||
* Methods-[http://download.oracle.com/javase/1.4.2/docs/api/java/lang/reflect/Method.html 'Method CLass'] | |||
* Constructors-[http://download.oracle.com/javase/1.4.2/docs/api/java/lang/reflect/Constructor.html 'Constructor Class'] | |||
* Arrays-[http://download.oracle.com/javase/1.4.2/docs/api/java/lang/reflect/Array.html 'Array Class'] | |||
===Illustration of Reflection in Java through Examples=== | ===Illustration of Reflection in Java through Examples=== | ||
Line 222: | Line 286: | ||
*'''Class''' | *'''Class''' | ||
Each class or interface in Java is described by a Class object.It contains methods to obtain | Each class or interface in Java is described by a Class object.It contains methods to obtain details about the class like name, parent class, constructors, fields, methods, interfaces implemented etc. | ||
To obtain the class that an object belongs to, invoke the method Class getClass()(returns 'Class') of the 'Object' class (superclass of all the Java classes hierarchy) | To obtain the class that an object belongs to, invoke the method Class getClass()(returns 'Class') of the 'Object' class (superclass of all the Java classes hierarchy). | ||
<pre>String myStr = "HelloWorld"; | <pre>String myStr = "HelloWorld"; | ||
Line 231: | Line 295: | ||
The property ".class"(available for every java class) returns a Class object for the class. | The property ".class"(available for every java class) returns a Class object for the class. | ||
<pre> | <pre> | ||
String myStr = "HelloWorld"; | String myStr = "HelloWorld"; | ||
Line 238: | Line 303: | ||
The wrapper classes (Integer, Boolean, Double,...) contain a ".TYPE" property that returns the Class object representing the primitive type. | The wrapper classes (Integer, Boolean, Double,...) contain a ".TYPE" property that returns the Class object representing the primitive type. | ||
<pre> | <pre> | ||
Class myClass = Integer.TYPE; // | Class myClass = Integer.TYPE; // | ||
Line 244: | Line 310: | ||
*'''Field''' | *'''Field''' | ||
The Field class describes the different attributes of a Java class field. Information such as | The Field class describes the different attributes of a Java class field. Information such as a field name, its type, and its accessibility can be obtained from a field object. It also contains methods to set and get the field's value for a given object | ||
Example | |||
'''Example:''' | |||
<pre> | <pre> | ||
Line 263: | Line 331: | ||
Field f = flist[i]; | Field f = flist[i]; | ||
System.out.println("name | System.out.println("name= " + f.getName()); | ||
System.out.println("decl class = " + f.getDeclaringClass()); | |||
System.out.println("decl class = " + | System.out.println("type = " + f.getType()); | ||
System.out.println("type | } | ||
} | } | ||
catch (Throwable e) { | catch (Throwable e) { | ||
Line 278: | Line 343: | ||
} | } | ||
The output of the program is: | |||
name = i | |||
decl class = MyfieldClass | decl class = MyfieldClass | ||
type = double | type = double | ||
Line 289: | Line 354: | ||
type = class java.lang.String | type = class java.lang.String | ||
</pre> | </pre> | ||
Line 296: | Line 360: | ||
The Method class is used to obtain information(the method name, its type, its accessibility, and its parameter types) about class methods.We can even invoke the method on a particular object and pass a set of parameters to it. | The Method class is used to obtain information(the method name, its type, its accessibility, and its parameter types) about class methods.We can even invoke the method on a particular object and pass a set of parameters to it. | ||
'''Example:''' | |||
<pre> | <pre> | ||
import java.lang.reflect.*; | import java.lang.reflect.*; | ||
Line 333: | Line 398: | ||
} | } | ||
} | } | ||
The output of the program is: | The output of the program is: | ||
name = myMethod | name = myMethod | ||
decl class = class myMethodClass | decl class = class myMethodClass | ||
Line 352: | Line 416: | ||
</pre> | </pre> | ||
*'''Constructor''' | |||
The Constructor class can be used to obtain information(parameter types, number of parameters, and accessibility) about class constructors.We can also invoke the constructor to create new object instances. | |||
'''Example:''' | |||
<pre> | <pre> | ||
import java.lang.reflect.*; | import java.lang.reflect.*; | ||
Line 374: | Line 439: | ||
Constructor ct = clist[i]; | Constructor ct = clist[i]; | ||
System.out.println("name= " + ct.getName()); | System.out.println("name= " + ct.getName()); | ||
System.out.println("Declaring Class Name = " + | System.out.println("Declaring Class Name = " + ct.getDeclaringClass()); | ||
Class pTypes[] = ct.getParameterTypes(); | Class pTypes[] = ct.getParameterTypes(); | ||
for (int j = 0; j < pTypes.length; j++) | for (int j = 0; j < pTypes.length; j++) | ||
System.out.println("param #" | System.out.println("param #" + j + " " + pTypes[j]); | ||
} | } | ||
} | } | ||
Line 389: | Line 452: | ||
} | } | ||
} | } | ||
Output: | |||
Name=MyConstructor | Name=MyConstructor | ||
Declaring Class name=MyConstructor | Declaring Class name=MyConstructor | ||
</pre> | </pre> | ||
===Applications of Reflection in Java=== | ===Applications of Reflection in Java=== | ||
Many sophisticated Java applications rely on | Many sophisticated Java applications rely on Reflection. Apart from the general benefits of Reflection, listed below are a few which are specific to Java. | ||
* Reflection is used extensively in protocols like [http://www.w3schools.com/soap/soap_intro.asp SOAP] | * Reflection is used extensively in protocols like [http://www.w3schools.com/soap/soap_intro.asp SOAP] | ||
*Whenever we drag-and-drop an object in an [http://en.wikipedia.org/wiki/Integrated_development_environment IDE] to use it in a form, Reflection is used behind the scenes. | *Whenever we drag-and-drop an object in an [http://en.wikipedia.org/wiki/Integrated_development_environment IDE] to use it in a form, Reflection is used behind the scenes. | ||
*Java Beans | *Java Beans | ||
*It is used in Debuggers and Test Tools which require examining the private members | *It is used in Debuggers and Test Tools which require examining the private members | ||
*Method can be easily invoked methods by their names, it is widely used in web, when invoking getters and setters by property names mentioned on jsp/jsf pages. | *Method can be easily invoked methods by their names, it is widely used in web, when invoking getters and setters by property names mentioned on jsp/jsf pages. | ||
Line 413: | Line 475: | ||
* '''Extensibility Features:''' An application may make use of external, user-defined classes by creating instances of extensibility objects using their fully-qualified names. | * '''Extensibility Features:''' An application may make use of external, user-defined classes by creating instances of extensibility objects using their fully-qualified names. | ||
* '''Class Browsers and Visual Development Environments''' A class browser will able to enumerate the members of classes and visual development environments can benefit from making use of type information available in reflection to help the developer in writing correct code. | * '''Class Browsers and Visual Development Environments''' A class browser will able to enumerate the members of classes and visual development environments can benefit from making use of type information available in reflection to help the developer in writing correct code. | ||
* '''Debugging:''' Debuggers and Test Tools Debuggers need to be able to examine private members on classes. Test harnesses can make use of reflection to systematically call a discoverable set APIs defined on a class, to insure a high level of code coverage in a test suite. | * '''Debugging:''' [http://en.wikipedia.org/wiki/Debugger Debuggers] and Test Tools Debuggers need to be able to examine private members on classes. Test harnesses can make use of reflection to systematically call a discoverable set APIs defined on a class, to insure a high level of code coverage in a test suite. | ||
* Reflection helps in keeping software [http://www.linfo.org/robust.html robust] | * Reflection helps in keeping software [http://www.linfo.org/robust.html robust] | ||
* It helps in making the applications more flexible and pluggable. | * It helps in making the applications more flexible and [http://solitarygeek.com/java/a-simple-pluggable-java-application pluggable]. | ||
* It helps in making the source code more readable and easier to understand. | * It helps in making the source code more readable and easier to understand. | ||
* It can simplify source code and design. | * It can simplify source code and design. | ||
Line 428: | Line 490: | ||
*'''Exposure of Internals:''' Since reflection allows code to perform operations that would be illegal in non-reflective code, such as accessing private fields and methods, the use of reflection can result in unexpected side-effects, which may render code dysfunctional and may destroy portability. Reflective code breaks abstractions and therefore may change behavior with upgrades of the platform. | *'''Exposure of Internals:''' Since reflection allows code to perform operations that would be illegal in non-reflective code, such as accessing private fields and methods, the use of reflection can result in unexpected side-effects, which may render code dysfunctional and may destroy portability. Reflective code breaks abstractions and therefore may change behavior with upgrades of the platform. | ||
*Compile-check features are lost. You can't be sure you're operating the right amount of parameters, their types, you even can't be sure the method you call exists. | *[http://en.wikipedia.org/wiki/Compiler Compile]-check features are lost. You can't be sure you're operating the right amount of parameters, their types, you even can't be sure the method you call exists. | ||
==MetaProgramming== | ==MetaProgramming== | ||
Line 434: | Line 496: | ||
The greek prefix [http://en.wikipedia.org/wiki/Meta 'Meta'] refers to knowledge about knowledge. [http://en.wikipedia.org/wiki/Metaprogramming Metaprogramming] means programs can create new code at runtime and run the code that is written. Program that writes a program.The related technique of metaprogramming allows one to create new program entities, such as methods or classes, at run time. | The greek prefix [http://en.wikipedia.org/wiki/Meta 'Meta'] refers to knowledge about knowledge. [http://en.wikipedia.org/wiki/Metaprogramming Metaprogramming] means programs can create new code at runtime and run the code that is written. Program that writes a program.The related technique of metaprogramming allows one to create new program entities, such as methods or classes, at run time. | ||
==See more== | |||
* http://download.oracle.com/javase/tutorial/reflect/ | |||
* http://msdn.microsoft.com/en-us/library/f7ykdhsy.aspx | |||
* http://odetocode.com/articles/288.aspx | |||
* http://www.jvoegele.com/software/langcomp.html | |||
* http://java.sys-con.com/node/36688 | |||
==References== | |||
* http://courses.ncsu.edu/csc517//common/lectures/notes/lec11.pdf | |||
http://download.oracle.com/javase/ | * http://ruby-doc.org/core/ | ||
* http://download.oracle.com/javase/1.4.2/docs/api/java/lang/reflect/package-summary.html | |||
* http://en.wikipedia.org/wiki/Reflection_(computer_programming) | |||
* http://stackoverflow.com/questions/4459345/disadvantages-advantages-of-reflection | |||
* http://java.sun.com/developer/technicalArticles/ALT/Reflection/ |
Latest revision as of 22:17, 20 October 2011
Introduction
Here we mainly focus on the lecture 11 of CSC 517 which is Reflection in Ruby. Some of the the examples used are the same as mentioned in the class notes and are elaborated in more detail. We also cover additional information on Reflection in Java,its applications and the advantages and disadvantages of Reflection in general.
Reflection
Reflection allows program entities to discover things about themselves through introspection. In other words,Reflection is the ability of a program to determine information about an object at runtime. The information may include the following :
- The type of the object
- Inheritance structure
- Methods it contains.
- Number of parameters of the methods,types of parameters, return types.
- Names and types of the attributes of the object.
Reflection is supported by many Object-oriented programminglanguages in various forms. Powerful and flexible reflection mechanisms are exhibited by Smalltalk, Ruby and Python. Java also supports reflection. But reflection in java is verbose and is not as flexible and dynamic as these languages. C++ allows a program to determine the type of an object at run-time. Thus it does support reflection but in a limited form only. Eiffel also has support for a limited form of reflection which includes the ability to determine the features contained in an object.
Reflection in Ruby
In Ruby, reflection is simpler because it is done using the language mechanisms ie <object>.methods gives the list of methods. This is in contrast to reflection in java which is much more verbose because we need to use class names,method names,parameter names etc.
Examples of Reflection in Ruby
3.1419.methods #gives the list of methods of the float number. irb(main):005:0> 3.1419.methods => [:to_s, :coerce, :-@, :+, :-, :*, :/, :quo, :fdiv, :%, :modulo, :divmod, :**, :==, :===, :<=>, :>, :>=, :<, :<=, :eql?, :hash, :to_f, :abs, :magnitude, :zero ?, :to_i, :to_int, :floor, :ceil, :round, :truncate, :nan?, :infinite?, :finite? , :numerator, :denominator, :to_r, :rationalize, :arg, :angle, :phase, :singleto n_method_added, :i, :+@, :div, :remainder, :real?, :integer?, :nonzero?, :step, :to_c, :real, :imaginary, :imag, :abs2, :rectangular, :rect, :polar, :conjugate, :conj, :between?, :nil?, :=~, :!~, :class, :singleton_class, :clone, :dup, :ini tialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust, :untruste d?, :trust, :freeze, :frozen?, :inspect, :methods, :singleton_methods, :protecte d_methods, :private_methods, :public_methods, :instance_variables, :instance_var iable_get, :instance_variable_set, :instance_variable_defined?, :instance_of?, : kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :respond_to_missing?, :extend, :display, :method, :public_method, :define_singleton_method, :__id__, :object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exe c, :__send__]
This is an example of discovering things about 3.1459 at runtime.(Reflection).Using Reflection,we can act on information during runtime without compiling it in. Information needed can be found out at run-time instead of writing code at compile time.
Example:
puts "hello".class #returns the class of object "hello" Output: =>String
Example:
puts "hello".class.superclass #returns the superclass of the String class Output: =>Object
Example:
puts 100.class # print the class of 100 >> Fixnum puts 98343098452405890454.class #prints the class of 98343098452405890454 >> Bignum puts 123456789012345.kind_of? Integer # >> true puts 123456789012345.instance_of? Integer # >> false puts 123456789012345.instance_of? Bignum >> true #instance_of? is a method of Object.returns true if the object is an instance of the #given class
Difference between Fixnum and Bignum in Ruby
A Fixnum stores Integer values which can be represented in a native machine word (minus 1 bit). If an operation on a Fixnum results in a value that exceeds the range, the value is automatically converted to a Bignum.
When Fixnum objects are assigned or passed as parameters, the actual objects are passed, rather than references to the objects. There is only one Fixnum object instance for a given integer value
Bignum objects are used to store values of integers outside the range of Fixnum. They are created automatically when encountered with integer calculations that would overflow a Fixnum. When a calculation involving Bignum objects returns a result that will fit in a Fixnum, the result is automatically converted.
OO Languages distinguish between a primitive and referencewith help of a leading or trailing bit. ie One bit indicates if the remaining bits store a primitive or a reference and the remaining bits represent the value. In numeric calculations, most of numbers are primitives so primitives can be used directly avoiding the overhead of indirection. One main difference between Fixnum and Bignum is that Fixnum can be stored in 1 machine word. If the object cannot be stored in a machine word then Bignum is used. In case of Bignum a reference to the actual object is stored.In contrast to Fixnum objects, objects references to objects are used for parameter passing.
Example:
puts string.ancestors #returns the ancestors of the string class Output: String Comparable Object Basic Object Kernel
Comparable which is an ancestor of the String class is a mixin .It is used to provide the comparable functionality (operations like <,>,<=,>= etc)to the String class based on the definition of the rocket method.
Object is the superclass of all classes.Its methods are available to all classes unless explicitly overridden. It provides methods like to_s,eql? etc.
Basic Object is the parent class of all classes in ruby including Object class. It is an explicit blank class.
Kernel is a module is included by class Object(hence a mixin). Its methods are available in all Ruby objects.
Fixnum.ancestors #returns the ancestors of Fixnum. => [Fixnum, Integer, Numeric, Comparable, Object, Kernel, BasicObject]
Integeris the basic for Fixnum and Bignum which are two concrete classes that hold whole numbers in ruby.
Numeric is a class which is used to provide methods like abs,floor,ceil,modulo,unary +,unary - etc. ie methods which can be performed on numbers in general.
Comparable which is an ancestor of the Fixnum class is a mixin.It is used to provide the comparable functionality (operations like <,>,<=,>= etc)to the FixNum class based on the definition of the rocket method.
We have discussed the Object and BasicObject classes in the above example.
Note: It is useful to print out the name of a class while debugging. A class of an object should not be tested while debugging in objected oriented programming. It is advised to use polymorphism to replace code that tests the class of an object and performs certain things.
Example:
if s.kind_of? Integer then this_method else that_method end #this is not a good practice.Should be replaced by [http://en.wikipedia.org/wiki/Polymorphism_(computer_science) polymorphism].
Assignment
In some languages like C, C++, or Ada, an assignment statement like x = y is interpreted as copying the contents of variable y into the variable x. It is generally required that x,y should be of the same type and size. But it is allowed in certain cases when the variables are of similar types.In C++, if the sizes are different say ,size of x is less than the size of y there will be a loss of data during assignment.(Slicing).
Ruby exhibits dynamic binding, not static binding ie the type of the object in a variable is determined at runtime but not at compile time. Therefore in Ruby, x = y can be 'interpreted as bind x to the same object that y is bound to'. The assignment operation is implemented by copying the reference stored in y into x.
Thus in Ruby,assignments physically copy references, but not the objects.
Obtaining Reference to a method in Ruby
A reference to a method can be obtained by using the method method in the class Object. It is available to all classes, since Object is the super class of all classes. The reference thus obtained can be used to invoke that particular method.
Example:
str = "Hello, World" #The name of the method(as a symbol) has to be passed as a parameter to 'method' m = str.method(:upcase) # returns a Method object which is a closure. puts m.call #returns "HELLO,WORLD"
In the above example,a reference to the method upcase of the String class is obtained by passing the symbol:upcase to the 'method' method of the String class. The reference(m) can then be used to invoke the method 'upcase' on the string object. Note that in the above example name of the method passed as a symbol.This is because symbols are immutable and every instance of a particular symbol is the same symbol. Thus symbols cannot appear in the left side of an assigment.In contrast,every instance of a particular string is a different string and hence has a different object id as seen in the example below.
Example:
irb(main):009:0> puts :mysymbol.object_id 332648 => nil irb(main):010:0> puts :mysymbol.object_id #Note that 2 occurrences of the same symbol 332648 # yielded same object id unlike strings (shown next) => nil irb(main):011:0> puts "mystring".object_id 21196488 => nil irb(main):012:0> puts "mystring".object_id 20959140
Applications of passing methods as parameters
Quadrature integration Here we compute the area under a curve say f(x) between two points say 'a' and 'b' by dividing the region under the curve into 'n' small rectangles with the heights parallel to the y axis.ie The length a to b is divided into n intervals.The area of each rectangle can be obtained by multiplying the height and the width.Height is the average of the values of f(x) at the two end points of the interval.Width is the length of the interval . Sum of the areas of all the rectangles gives us an approximation of the area of the area under f(x).
Example: Suppose we need to compute the area under a curve described by some function, x2 + 2x + 3 between say 10 and 20. Then we can define a method poly for the Float class which returns the evaluation of the polynomial at that point.
class Float def poly self*self + 2*self + 3 end end
And to compute the area,we pass poly to an integration method which takes the method reference,end points between which the area is to be computed as the parameters
area = integrate(:poly, 10, 20) #calculates the area of the curve x2+2x+3 between the #points x=10 to x=20.
Intercepting calls to undefined methods
Ruby provides an option to intercept the call when a call to an undefined method is made on an object. Implementation of the method method_missingwithin the class definition provides this facility. This feature is not available in java. A class cast exception is thrown whenever a call to an undefined method is made. Ruby passes the name of the method called(which is unavailable) and the arguments passed to it as parameters to the method_missing method.
Example: In the following example, class Duck defines 'quack' and 'method_missing' methods. When an object d of Duck is created and quack is invoked on it,it executes the quack of Duck(as expected). But when 'bark' is invoked on it, method_missing is invoked.
class Duck def quack puts "Quack" end def method_missing(meth, *args) #handles calls to undefined methods puts "Sorry, I do not #{meth}" end end d = Duck.new d.quack >>Quack d.bark #bark is passed to method_missing since 'bark' method is not defined in Duck class. >> Sorry, I do not bark
Example of an interesting usage of method_missing: “Roman method_missing”.
class Roman DIGITS = { 'I' => 1, 'V' => 5, 'X' => 10, 'L' => 50, 'C' => 100, 'D' => 500, 'M' => 1000, } def roman_to_integer(roman_string) prev = nil #prev stores the previous value in roman string roman_string.to_s.upcase.split(//).reverse.inject(0) do |memo, digit| if digit_value = DIGITS[digit] #checks if the integer value is present in the hash if prev && prev > digit_value memo -= digit_value else memo += digit_value end prev = digit_value end memo end end def method_missing(method) str = method.id2name roman_to_integer(str) end end r=Roman.new r.XV Output : =>15
In this example we declare a class Roman containing a hash called DIGITS which maps Roman symbols with the corresponding integers. The class also contains the methods method_missing and roman_to_integer. When an object of Roman class( say r) is created and when we invoke method XV on r (ie r.XV) ,method_missing(:XV) is invoked since the Roman class has no method named XV. Inside method_missing, the symbol is converted to "XV"(string) and roman_to_str("XV") is called. In roman_to_str method, the string is converted to uppercase, split into an array and the array is reversed. The inject operator then passes each element (of the array) and an accumulator value (memo)to the block.The initial value of memo is 0. For each element,if the previous digit_value exists and is greater than the current digit_value,the current digit_value is added to memo. Else current digit_value is subtracted from memo.The result becomes the new value for memo. At the end of the iteration, the final value of memo is the integer value of the Roman string.
Reflection in Java
Reflection in Java is much more verbose than in ruby.It is an advanced feature of the Java environment. Reflection is achieved using the Reflection API.The verbosity of reflection in java may be associated with the usage of the library for reflection.
Reflection is an advanced feature of the Java environment. It gives runtime information about objects, classes, and interfaces. Some of the questions that can be answered using reflection in java:
- Which class does an object belong to?
- What is the description of a given class name?
- What are the fields in a given class?
- What is the type of a field?
- What are the methods in a class?
- What are the parameters of a method?
- What are the constructors of a given class?
- Constructing an object using a given constructor
- Invoking an object's method using such-and-such parameters.
- Assigning a value to an object's field.
- Dynamically creating and manipulating arrays.
Java Reflection Classes
All Reflection classes (With the exception of the class Class that resides in the default Java package) are contained in the package java.lang.reflect.
Following are some of the classes used to various represent members of a class.:
- Classes-'Class'
- Class Fields-'Field Class'
- Methods-'Method CLass'
- Constructors-'Constructor Class'
- Arrays-'Array Class'
Illustration of Reflection in Java through Examples
- Class
Each class or interface in Java is described by a Class object.It contains methods to obtain details about the class like name, parent class, constructors, fields, methods, interfaces implemented etc.
To obtain the class that an object belongs to, invoke the method Class getClass()(returns 'Class') of the 'Object' class (superclass of all the Java classes hierarchy).
String myStr = "HelloWorld"; Class theClass = myStr.getClass(); // 'theClass' now contains 'String'
The property ".class"(available for every java class) returns a Class object for the class.
String myStr = "HelloWorld"; if (myStr.getClass()==String.class) System.out.println("The object is a String"); // prints "The object is a String"
The wrapper classes (Integer, Boolean, Double,...) contain a ".TYPE" property that returns the Class object representing the primitive type.
Class myClass = Integer.TYPE; //
- Field
The Field class describes the different attributes of a Java class field. Information such as a field name, its type, and its accessibility can be obtained from a field object. It also contains methods to set and get the field's value for a given object
Example:
import java.lang.reflect.*; public class MyfieldClass { int i = 100; String s = "Hello World"; public static void main(String args[]) { try { Class cls = Class.forName("MyfieldClass"); Field flist[]= cls.getDeclaredFields(); for (int i = 0; i < flist.length; i++) { Field f = flist[i]; System.out.println("name= " + f.getName()); System.out.println("decl class = " + f.getDeclaringClass()); System.out.println("type = " + f.getType()); } } catch (Throwable e) { System.err.println(e); } } } The output of the program is: name = i decl class = MyfieldClass type = double name = s decl class = MyfieldClass type = class java.lang.String
- Method
The Method class is used to obtain information(the method name, its type, its accessibility, and its parameter types) about class methods.We can even invoke the method on a particular object and pass a set of parameters to it.
Example:
import java.lang.reflect.*; public class myMethodClass { private int myMethod(int y, int x) { return x+y; } public static void main(String args[]) { try { Class cls = Class.forName("myMethodClass"); Method mlist[] = cls.getDeclaredMethods(); for (int i = 0; i < mlist.length;i++) { Method m = mlist[i]; System.out.println("name= " + m.getName()); System.out.println("decl class = " +m.getDeclaringClass()); Class pt[] = m.getParameterTypes(); for (int j = 0; j < pt.length; j++) System.out.println("param #" + j + " " + pt[j]); System.out.println("return type = " + m.getReturnType()); } } catch (Throwable e) { System.err.println(e); } } } The output of the program is: name = myMethod decl class = class myMethodClass param #0 int param #1 int return type = int name = main decl class = class myMethodClass param #0 class [Ljava.lang.String; return type = void
- Constructor
The Constructor class can be used to obtain information(parameter types, number of parameters, and accessibility) about class constructors.We can also invoke the constructor to create new object instances.
Example:
import java.lang.reflect.*; public class Myconstructor { public Myconstructor() { } public static void main(String args[]) { try { Class c = Class.forName("Myconstructor"); Constructor clist[]= c.getDeclaredConstructors(); for (int i = 0; i < clist.length; i++) { Constructor ct = clist[i]; System.out.println("name= " + ct.getName()); System.out.println("Declaring Class Name = " + ct.getDeclaringClass()); Class pTypes[] = ct.getParameterTypes(); for (int j = 0; j < pTypes.length; j++) System.out.println("param #" + j + " " + pTypes[j]); } } catch (Throwable e) { System.err.println(e); } } } Output: Name=MyConstructor Declaring Class name=MyConstructor
Applications of Reflection in Java
Many sophisticated Java applications rely on Reflection. Apart from the general benefits of Reflection, listed below are a few which are specific to Java.
- Reflection is used extensively in protocols like SOAP
- Whenever we drag-and-drop an object in an IDE to use it in a form, Reflection is used behind the scenes.
- Java Beans
- It is used in Debuggers and Test Tools which require examining the private members
- Method can be easily invoked methods by their names, it is widely used in web, when invoking getters and setters by property names mentioned on jsp/jsf pages.
Advantages of Reflection
Reflection has many advantages some of which have been listed below:
- Extensibility Features: An application may make use of external, user-defined classes by creating instances of extensibility objects using their fully-qualified names.
- Class Browsers and Visual Development Environments A class browser will able to enumerate the members of classes and visual development environments can benefit from making use of type information available in reflection to help the developer in writing correct code.
- Debugging: Debuggers and Test Tools Debuggers need to be able to examine private members on classes. Test harnesses can make use of reflection to systematically call a discoverable set APIs defined on a class, to insure a high level of code coverage in a test suite.
- Reflection helps in keeping software robust
- It helps in making the applications more flexible and pluggable.
- It helps in making the source code more readable and easier to understand.
- It can simplify source code and design.
- Expensive conditional code can be reduced/removed.
Disadvantages of Reflection
- Performance Overhead: Reflection involves types that are dynamically resolved due to which certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts. Hence, they should be avoided in sections of code which are called frequently in performance-sensitive applications.
- Security Restrictions: Reflection requires a runtime permission which may not be present when running under a security manager. This is in an important consideration for code which has to run in a restricted security context, such as in an Applet in Java.
- Exposure of Internals: Since reflection allows code to perform operations that would be illegal in non-reflective code, such as accessing private fields and methods, the use of reflection can result in unexpected side-effects, which may render code dysfunctional and may destroy portability. Reflective code breaks abstractions and therefore may change behavior with upgrades of the platform.
- Compile-check features are lost. You can't be sure you're operating the right amount of parameters, their types, you even can't be sure the method you call exists.
MetaProgramming
The greek prefix 'Meta' refers to knowledge about knowledge. Metaprogramming means programs can create new code at runtime and run the code that is written. Program that writes a program.The related technique of metaprogramming allows one to create new program entities, such as methods or classes, at run time.
See more
References
- http://courses.ncsu.edu/csc517//common/lectures/notes/lec11.pdf
- http://ruby-doc.org/core/
- http://download.oracle.com/javase/1.4.2/docs/api/java/lang/reflect/package-summary.html
- http://en.wikipedia.org/wiki/Reflection_(computer_programming)
- http://stackoverflow.com/questions/4459345/disadvantages-advantages-of-reflection
- http://java.sun.com/developer/technicalArticles/ALT/Reflection/