Open Java A Classbased Macro System for Java
Open Java A Class-based Macro System for Java
Reflection o o o Reflection is a technique for changing the program behavior according to another program. From software engineering viewpoint, reflection is a tool for separation of concerns. It can be used for letting programmers write a program with higher-level abstraction and with good modularity.
Drawbacks o However, previous reflective systems do not satisfy all the requirements in software engineering: n n o can be used for implementing only limited kinds of separation of concerns. involves runtime penalties. Reflective systems should enable more finegrained program weaving and perform as much reflective computation as possible at compile time for avoiding runtime penalties.
Macro system +++++ o A typical tool for manipulating a program at compile time o Performs textual substitution so that a particular aspect of a program is separated from the rest of that program. o For example, the C/C ++ macro system allows to separate the definition of a constant value from the rest of a program, in which that constant value is used in a number of distinct lines. o Done at compile time => does not imply any runtime penalties. -----o o Not sophisticated; since macros can deal with only textual representation of a program Program manipulation depending on the semantic contexts of the program cannot be implemented with macros.
Open. Java: short description o o o A compile-time reflective system for not only behavioral reflection but also structural reflection. A key idea is that macros (meta programs) deal with class metaobjects representing logical entities of a program instead of a sequence of tokens. Since the class metaobjects abstract both textual and semantic aspects of a program, macros in Open. Java can implement more finegrained program weaving than in previous reflective systems.
Some definitions in Open. Java o o o Metaobject is an object that represents a logical structure of a class definition in the source code. Metaclass is a customized definition of a metaobject for describing a macro expansion. Metaprogram of a macro is described as a metaclass. Metaobject manages macro expansion of the class it represents. Macro expansion by Open. Java is divided into two: the first one is macro expansion of class declarations (callee-side), and the second one is that of expressions accessing classes(caller-side).
Applying Macros o o o Every metaclass must inherit from the metaclass OJClass, which is a built-in class of Open. Java. The translate. Definition() method inherited from OJClass, invoked by the system to make macro expansion. instantiates M clause in a class declaration, creates an instance of the metaclass M (metaobject) and assigns it to the declared class. translate. Definition() declared in OJClass does not perform any translation and must be overriden to perform any macro expansion. The result of the macro expansion is an ordinary Java program.
(Example (1 Application of a macro in Open. Java. class My. Menu. Listener instantiates Observer. Class extends My. Object implements Menu. Listener {. . } A macro in Open. Java. class Observer. Class extends OJClass { void translate. Definition() {. . . }
(Example (2 translate. Definition() in Observer. Class. void translate. Definition() { OJMethod[] m = this. get. Methods(this); for(int i = 0; i <m. length; ++i) { OJModifier modif = m[i]. get. Modifiers(); if (modif. is. Abstract()) { OJMethod n = new OJMethod(this, m[i]. get. Modifiers(). remove. Abstract(), m[i]. get. Return. Type(), m[i]. get. Name(), m[i]. get. Parameter. Types(), m[i]. get. Exception. Types(), make. Statement. List("return; ")); this. add. Method(n); } } }
Hiding Syntactical Information o Some elements in the grammar represent the same element in a logical structure of the language. If one of these element is edited, the others are also edited. n o Example: set. Name() modifying the name of the class changes not only the class name after the class keyword in the class declaration but also changes the name of the constructors. One can use various syntax for describing the logically same thing. Syntactical differences are absorbed by the metaobjects. n Example: String[] a; String b[]; get. Type() on the metaobjects representing a and b returns a class metaobject representing the array type of the class String.
Table 1. Member methods in OJClass. for non-class types. boolean is. Interface() Tests if this represents an interface type. boolean is. Array() Tests if this represents an array type. boolean is. Primitive() Tests if this represents a primitive type. OJClass get. Component. Type() Returns a class metaobject for the type of array components.
Table 2. Member methods in OJClass for introspection. o o String get. Package. Name() n o o Returns the superclass declared explicitly or implicitly. Returns all the declared superinterfaces. Statement. List get. Initializer() n Returns all the static initializer statements. Returns all the constructors declared explicitly or implicitly. OJClass[] get. Declared. Classes() n o Returns all the declared methods. OJConstructor[] get. Declared. Constructors() n o Returns all the declared elds. OJMethod[] get. Declared. Methods() n Returns the modiers for this class. OJClass[] get. Declared. Interfaces() n o Returns the unqualied name of this class. OJClass get. Superclass() n o o OJModifier get. Modifiers() n o n String get. Simple. Name() n o Returns the package name this class belongs to. OJField[] get. Declared. Fields() Returns all the member classes (inner classes). OJClass get. Declaring. Class() n Returns the class declaring this class (outer class).
Table 3. Member methods in OJClass for modifying the class. o String set. Simplename (String name) n o o OJClass[] set. Interfaces (OJClass[] faces) n o o Sets the class modifiers. Sets the superclass. Sets the superinterfaces to be declared. OJField remove. Field (OJField field) n Removes the given eld from this class declaration. OJMethod remove. Method (OJMethod method) n OJClass set. Superclass (OJClass clazz) n o Sets the unqualied name of this class. OJModifier set. Modifiers (OJModifier modifs) n o OJConstructor remove. Constructor (OJConstructor constr) n o Adds the given eld to this class declaration. OJMethod add. Method (OJMethod method) n o Removes the given constructor from this class declaration. OJField add. Field (OJField field) n o Removes the given method from this class declaration. Adds the given method to this class declaration. OJConstructor add. Constructor (OJConstructor constr) n Adds the given constructor to this class declaration.
Table 4. 4. Basicmethodsin in OJMethod. o String get. Name() n o o Returns the parameter types in declaration order. OJClass[] get. Exception. Types() n o Returns the return type. OJClass[] get. Parameter. Types() n o Returns the modiers for this method. OJClass get. Return. Type() n o Returns the name of this method. OJModifier get. Modifiers() n String set. Name (String name) n o o Returns the parameter variable names in declaration order. o Sets the parameter types in declaration order. OJClass[] set. Exception. Types() n Sets the types of the exceptions declared to be thrown. String[] set. Parameter. Variables() n o Sets the return type. OJClass[] set. Parameter. Types() n o Sets the method modiers. OJClass set. Return. Type() n o Sets the name of this method. OJModifier set. Modifiers(OJModifier modifs) n Returns the types of the exceptions declared to be thrown. String[] get. Parameter. Variables() n o Sets the parameter variable names in declaration order. Statement. List set. Body() n Sets the statements of the method body.
Table 5. Member Methods in OJClass for introspection (2) o OJClass[] get. Interfaces() n o Returns all the interfaces implemented by this class or the all the superinterfaces of this interface. boolean is. Assignable. From(OJClass clazz) n o Determines if this class/interface is either the same as, or is a superclass or superinterface of, the given class/interface. OJMethod[] get. Methods(OJClass situation) n o OJMethod get. Method(String name, OJClass[] types, OJClass situation) n o Returns all the class available from the given situation, including those declared and those inherited from superclasses/superinterfaces. Returns the specified method available from the given situation. OJMethod get. Invoked. Method(String name, OJClass[] types, OJClass situation) n Returns the method, of the given name, invoked by the given arguments types, and
Caller-side Translation When the class A creates object of class B, method expand. Allocation() of metaobject of class B is invoked. o expand. Allocation() receives the expression of object of class B creation and returns the modified expression. Table 6. Member Methods for Each Place Applied the Macro-Expansion to o Member method Place applied the macro expansion to translate. Definition() Class declaration expand. Allocation() Class instance allocation expression expand. Array. Allocation() Array allocation expression expand. Type. Name() Class name expand. Method. Call() Method class expression expand. Field. Read() Field-read expression expand. Field. Write() Field-write expression expand. Casted. Expression() Casted expression from this type expand. Cast. Expression() Casted expression to this type
Translation Mechanism o Given a source program, the processor of Open. Java: 1. Analyzes the source program to generate a class metaobject for each class. 2. Invokes the member methods of class metaobjects to perform macro expansion. 3. Generates the regular Java source program reflecting the modification made by the class metaobjects. 4. Executes the regular Java compiler to generate the corresponding byte code.
The Order of Translations o o o Caller-side and callee-side translation may intersect, creating ambiguousity. First the system invokes translate. Definition() as callee-side translation. Then it apply caller-side translation. n Example: 1. 2. translate. Definition() changes an instance creation expression of class X into Y’s expand. Allocation() defined in the metaclass of X is not performed.
Dealing with Separate Compilation o o Program can be split into several files. In a caller-side translation, metaobject must access a metaoject of another class. n o Example: If there is no source code for a class C, the system cannot specifiy the metaclass of C. Therefore expand. Allocation() on instance creation expressions of C cannot be performed. When compiling separate files, metalevel information is preserved in the special class of each. class file.
Syntax Extension o o o Metaclass can introduce new class/member modifiers and clauses. New clauses must start with the special word at some limited positions of the regular Java grammar. The newly introduced clauses are valid only in the parts related to instances of the metaclass.
Syntax Extension (2) o In a class declaration (callee-side), the positions allowed to introduce new clauses are: n n n o before the block of member declarations, before the block of method body in each method declaration, after the field variable in each field declaration. And in other class declarations (caller-side), the allowed position is: n after the name of the class.
Syntax Extension (Example) class Vector. Stack instantiates Adapter. Class adapts Vector in v to Stack {. . } static Syntax. Rule get. Decl. Suffix(String keyword) { if (keyword. equals("adapts")) { return new Composite. Rule( new Type. Name. Rule(), new Prep. Phrase. Rule("in", new Identifier. Rule()), new Prep. Phrase. Rule("to", new Type. Name. Rule()) ); } return null; }
(Example (Hello world public class Hello { public static void main( String[] args ) { System. out. println( "main is called. " ); hello(); } static void hello() { System. out. println( "hello is called. " ); System. out. println( "Hello, world. " ); } }
(Example (Hello world) (2 public class Hello instantiates Verbose. Class { public static void main( String[] args ) { hello(); } static void hello() { System. out. println( "Hello, world. " ); } }
(Example (Hello world) (3 import openjava. mop. *; import openjava. ptree. *; public class Verbose. Class instantiates Metaclass extends OJClass { public void translate. Definition() throws MOPException { OJMethod[] methods = get. Declared. Methods(); for (int i = 0; i < methods. length; ++i) { Statement printer = make. Statement( "System. out. println( "" + methods[i] + " is called. " ); methods[i]. get. Body(). insert. Element. At( printer, 0 ); } } }
(Example (Hello world) (4 void Hello. main(String[]) is called. void Hello. hello() is called. Hello, world.
Example (Override. Checker. Class) public class My. Object instantiates Override. Checker. Class{ public overriding String to. String() { return "My. String"; } } public class My. Object. With. Error instantiates Override. Checker. Class { public overriding String to. Strung() { return "My. String"; } }
Example (Override. Checker. Class) (2) import openjava. mop. *; import openjava. ptree. *; public class Override. Checker. Class instantiates Metaclass extends OJClass { private static final String OVERRIDING = "overriding"; public static boolean is. Registered. Modifier( String keyword ) { if (keyword. equals( OVERRIDING )) return true; return OJClass. is. Registered. Modifier( keyword ); } public void translate. Definition() throws MOPException { OJMethod[] methods = get. Declared. Methods(); for (int i = 0; i < methods. length; ++i) { if (! methods[i]. get. Modifiers(). has( OVERRIDING )) continue; String name = methods[i]. get. Name(); OJClass[] ptypes = methods[i]. get. Parameter. Types(); try { get. Superclass(). get. Method( name, ptypes, this ); } catch (No. Such. Member. Exception e) { System. err. println( "warning: " + methods[i] + " doesn't " + "override any method in the superclasses. " ); } }}}
- Slides: 28