The introspective reflection library is a set of objects and classes that allow a program to access information about itself at compile or run time. For example, the program can know the class of an object, the methods and instance variables of that class, the parameter names and types of each method, and so on.
There is only one way a program can access information about itself at compile time: by sending messages to built-in object TheCompiler. This class object has the following methods:
LiteralStringNo is a class of the Abstract Syntax Tree of the compiler that represent
values of class String.
Each class in the
system is described by an object of ClassInfo or one of its subclasses. To get the object of ClassInfo that describes a class Person
we do
var ci : ClassInfo;
ci =
Person.getAssociatedClassInfo();
// print
"Person"
Out.writeln(
ci.getName() );
The class of an object can be got by calling method getClassObject:
var p : Person;
...
var any :
AnyClassObject;
any =
p.getClassObject();
// print
"Person"
Out.write(
any.getAssociatedClassInfo().getName() );
The methods of a class are got in the following way:
var ci : ClassInfo;
var p : Person;
var iter :
DS.Iter(ClassMethodInfo);
...
ci = p.getClassInfo();
iter =
ci.getMethods();
while iter.more()
do
Out.writeln( iter.next().getName() );
Instead of using the ClassInfo hierarchy to get information about classes, one can access information about individual objects, which includes class objects:
var ac : Account;
...
var objInfo : ObjectInfo;
objInfo =
ac.getInfo();
// list the
names of all instance variables of the object
var iter :
DS.Iter(ObjectInstanceVariableInfo);
iter =
objInfo.getInstanceVariables();
while iter.more() do
Out.writeln( iter.next().getName() );
var objMethodInfo :
ObjectMethodInfo;
// get info
about method "getBalance" of object ac
objMethodInfo =
objInfo.getMethod("getBalance", nil);
// calls method
"getBalance" of object ac. The balance
// returned is printed
Out.writeln( objMethodInfo.invoke(nil)
);
The exceptions this code could generate were
not considered.
MethodInfo InstanceVariableInfo AnyObjectInfo
|
Some classes of the Introspective Reflection Library |
The hierarchies of MethodInfo, InstanceVariableInfo , and AnyObjectInfo are shown in the table above. A subclass is put below a superclass and two columns at the right of it.
One can create and use an array whose element type will only be known at run time without using the reflection library. This is possible because all arrays are subclasses of class AnyArray . See the following code.
var any : Any =
integer;
var anArray :
AnyArray;
// creates a
10-element integer array
anArray =
array(any)[].new(10);
anArray.set(5, 0); //
anArray[0] = 5;
anArray.set(3, 1); //
anArray[1] = 3;
Out.writeln(
anArray.get(0) ); // print 5
If any does not refer to a class object at run time, an
exception will be thrown. All the classes of the introspective reflection
library are described in The Green Report .
None of
the functionalities of the introspective reflection library is new. However,
the library is well organized in a set of classes with several inheritance
hierarchies. Each method was carefully examined to discover in which class it
should be put. There is a sharp contrast between The Green IRL and The Java
Reflection API, which has several flaws:
The Green IRL has some interesting points:
proc invoke( vetArgs : array(Any)[] )
which does not requires the object as parameter
(only the arguments in vetArgs). Then a call to invoke of ObjectMethodInfo is faster than a call to invoke of ClassMethodInfo which
requires another parameter:
proc invoke( obj : Any; vetArgs : array(Any)[] )
This is important for efficient shell implementation;
var
anArray : AnyArray;
anArray = array(any)[].new(10);
any
should refer to a class object at run time or an exception will be thrown.
Class AnyArray has methods get and set for handling array elements.