CSC/ECE 517 Fall 2010/ch2 S24 NS
Metaprogramming in statically typed languages
What is Metaprogramming?
Metaprogramming is the technique that allows us to write programs that can manipulate other programs or themselves as a part of their data. Such programs help the programmer to avoid recompilations by executing their part of the work at compile time rather than at runtime.
The ability of a program to treat itself as a part of the data is known as reflection by virtue of which the program can modify its own structure and behavior. Often, metaprogramming and reflection are synonymous terms and one can be defined in the context of the other. Metalanguage is the language in which the metaprogram is written.
A most illustrative instance of metaprogramming is the use of Vectors in many languages, which are a set of multidimensional mathematical entities. Through metaprogramming, we can pass parameters to a generic class, the code for which will be generated by the compiler for each dimension of the Vector.
Example of Metaprogramming
Here is a simple example of metaprogramming in Ruby. Supposing we are having the following code in our ruby file.
COLORS = { :black => "000", :red => "f00", :green => "0f0", :yellow => "ff0", :blue => "00f", :magenta => "f0f", :cyan => "0ff", :white => "fff" }
The class can be defined as
class String
COLORS.each do |color,code|
define_method "in_#{color}" do "#{self}"
end
end
end
[3].code snippet for “Metaprogramming Ruby”
The above code generates new methods for the build in String class based on a list of colors and they wrap the particular String in the respective color by virtue of HTML tags.
In particular, we can use this code in our application as :
“ ’ Hello World’.in_blue”
which will print the text in blue color. This aspect of metaprogramming saves the programmer the tedious job of encoding each behavior in a type of method.
Metaprogramming in Java:
Metaprogramming in java comprises of three main components:
- Reflection
- Generics
- Annotations
Reflection in Java
The reflective nature of a Java program allows Java programs to introspect upon themselves and manipulate internal properties of the program. One tangible use of this feature is in JavaBeans in which a information about the classes are dynamically obtained via a Builder Tool as the classes are dynamically loaded. Reflection in Java is normally accomplished through the Reflection API which consists of the "Reflect" package and is available in the java.lang hierarchy.
Consider the following code
import java.lang.reflect.*; public class DumpMethods { public static void main(String args[]) { try { Class c = Class.forName(args[0]); Method m[] = c.getDeclaredMethods(); for (int i = 0; i < m.length; i++) System.out.println(m[i].toString()); } catch (Throwable e) { System.err.println(e); } } [8].Code snippet for “Java Reflection”
If it is invoked in the following manner
“java DumpMethods java.util.Stack”
The output will be:
public java.lang.Object java.util.Stack.push( java.lang.Object) public synchronized java.lang.Object java.util.Stack.pop() public synchronized java.lang.Object java.util.Stack.peek() public boolean java.util.Stack.empty() public synchronized int java.util.Stack.search(java.lang.Object) [8].Code snippet for “Java Reflection”
The method names of java.util.Stack class are listed with their parameters and return types
- Class.forName : It is a static method of Class that loads the specific class which, in this case, is the java.util.Stack class
- getDeclaredMethods: It is another method of Class that retrieves the list of methods and return them as objects defined in the Stack class
- Method: Method is another class of which an array of objects is created to hold the values of the returned objects
Generics in Java
Generic programming is a type of computer programming in which the algorithms are written to accommodate data types whose values are to be specified late. Such data types are instantiated only when the particular datatype is passed as a parameter to the Generic class.
In Java, code is not created for each type specific instance of a Generic like other statically typed languages like C++. Bytecode is generated only once for each function and class and the generic types are replaced by “Object”, which is a built in generic type.
How Generics are defined?
Consider the use of the List class to define generics. Then, it can be defined as
List <WrapperClass type> object = new ArrayList <WrapperClass type>
Wrapper Class may be String or Integer or similar class types based on the requirement
An example of the use of Generics is as follows
import java.util.*; public class BoxingGenericsExample { public static void main(String args[]) { HashMap<String,Integer> hm = new HashMap<String,Integer>(); hm.put("speed", 20); } } [9]. Code snippet for “Java Generics”
The HashMap can accommodate two values of String and Integer types which are declared using Generics
Generic Classes
It is possible to define classes in Generics
class GenericExample<T> { T ob; // declare an object of type T GenericExample(T o) //constructor initializing the object of T to the object passed as args { ob = o; } T getob() { return ob; } void showType() { System.out.println("Type of T is " + ob.getClass().getName()); } } public class GenDemo { public static void main(String args[]) { GenericExample<Integer> iOb= new GenericExample<Integer>(88); iOb.showType(); }} [10].Code snippet for “Java Generic Class”
At runtime the value of T will be the Integer class
Generic Interfaces and Methods
Similarly it is also possible to define interfaces and methods in Generics
public interface List<E> { void add(Ex); void display(); }
//Generic Method public static <T> void filter() { //Method code }
The main disadvantages of Generics are that parameter type information is not available at run time, and that automatically generated casts may fail when interoperating with ill-behaved legacy code so runtime safety is compromised.
Annotations in Java
Annotations are syntactic metadata which can be added to the java source code and can include classes, methods, variables and packages. This is another manifestation of the reflective nature of Java in which such annotations may be embedded in class files and retrieved at runtime. An annotation definition might look like this
public @interface TestAnnotation { // Property Definition here. }
‘@’ indicates the start of an annotation definition. The above annotation is an interface level annotation. This is specified in the declaration of an annotation itself and is known as “Annotating an Annotation” The compiler has a reserved set of annotations for syntactic purposes among which three are worth mentioning
@Deprecated
The annotated element is deprecated and no longer in use.
//Example of a deprecated annotation @Deprecated static void deprecatedMethod() { //code }
@Override
The annotated element is meant to be overridden in the superclass
//Example of a override annotation @Override int overriddenMethod() { //code }
@SuppressWarnings
The compiler has to suppress warnings which it would otherwise generate. This is usually done when a deprecated method is used and warnings from the compiler are not desired.
//Example of a suppress warning annotation // compiler not to generate a warning @SuppressWarnings("deprecation") void useDeprecatedMethod() { objectOne.deprecatedMethod(); //deprecation warning - suppressed }
Technical issues: Meta Programming with JAVA
Every time a user wishes to write a Java Bean object, following key steps should be implemented. This includes:
- Making the class serializable
- Ensuring the class has a default constructor
- Writing getters and/or setters for all properties
- Writing methods to register and unregister listeners for the bound properties
Unit tests are seldom written for getters and setters and generally the process is error prone. These shortcomings are overcome by code generating tools like XDoclet and Eclipse but they have their own limitations.All these tools use their own template language and their functionality is restricted to the behaviour of C/C++ macros. In a metaprogramming language, the template and the code it generates are implemented in one language only. It is therefore possible to extend the language itself, by adding new constructs, rather than developing the object hierarchy.
How to resolve this problem?
Attribute oriented programming
It is a program-level marking technique to be exploited to enable meta programming and address the challenges posed by it. Programmers can mark elements like classes and methods to indicate that they maintain application-specific or domain-specific semantics. Application's business logic is separated from domain specific semantics using attributes. By keeping the implementation details of those semantics from program code hidden, attributes increase the level of abstraction and reduce programming complexity. This results in simpler and more readable programs. The program elements associated with attributes are transformed to more detailed programs by a supporting tool. A supporting tool can be a preprocessor.
XDoclet
Users can add more meaning to the code by adding meta data to the java source code in special JavaDoc tags. This technique, also referred as Attribute Oriented Programming, is made possible in Java by XDoclet, an open source code generation engine. XDoclet works by parsing the source file and generating several artifacts from it. Artifacts can include XML descriptors and/or source code. Using the information provided in the source code and in its JavaDoc tags, template generate these files. XDoclet includes a core module and constantly growing number of modules. Whenever there is a requirement for a new component, new modules can be written easily using this feature. XDoclet has several advantages that has made it an instant hit with the programming community. To list a few advantages, that includes: Redundancy elimination: Users need to write only the business logic and XDoclet generates the support code and “boiler-plate” for it. Extensibility: XDoclet is designed for modular programming. On identifying repeatable code, users can write XDoclet templates to generate the necessary code. Better understanding of J2EE programs: Users need to implement the enterprise bean and XDoclet generates the necessary interfaces, value objects, struts for the user.
XDoclet was initially conceived as tool for creating EJBs. Over the course of time, it has evolved into a code generation engine making programming a lot easier.
public class Matrix { /** @todo need to handle the case where there is no spoon */ public void reload() { // … }}
Now to use the XDoclet code we have to insert a todo tag in the Ant Build file like the following
<target name="todo" depends="init"> <documentdoclet destdir="todo"> <fileset dir="${dir.src}"> <include name="**/*.java" /> [13]. Code snippet for “XDoclet”
Prior to the release of the Metadata Facility, XDoclet was used for attribute oriented programming approach in Java.
Metadata Facility
An advanced and a sophisticated technique for Attribute Oriented Programming in Java is through the Metadata Facility (JSR-175) [14] which is included in the J2SE version 5.0. It is actually an API (Application Programming Interface) for enabling annotations of fields, methods and classes and thus enabling developement tools and runtime libraries to run them in a specific desired way.
References
[1] “Metaprogramming in Java, C# and C++” by Patrik Lindegrén and Joakim Östlund
[2] “Meta Programming In Java” by Mika Haapakorpi
[3] http://en.wikipedia.org/wiki/Ruby_(programming_language)#Metaprogramming
[4] http://www.javabeat.net/articles/30-annotations-in-java-50-1.html
[5] http://download.oracle.com/javase/1.5.0/docs/guide/language/generics.html
[6] http://agiledeveloper.com/articles/GenericsInJavaPartI.pdf
[7] http://download.oracle.com/javase/tutorial/java/
[8] http://java.sun.com/developer/technicalArticles/ALT/Reflection/
[9] http://media.wiley.com/product_data/excerpt/02/04717771/0471777102.pdf
[10] http://www.java2s.com/Code/Java/Language-Basics/Overridingagenericmethodinagenericcl ass.html
[11] http://en.wikipedia.org/wiki/Attribute-Oriented_Programming
[12] http://xdoclet.sourceforge.net/xdoclet/index.html
[13] http://www.manning-source.com/books/walls/walls_ch02.pdf
[14] http://en.wikipedia.org/wiki/A_Metadata_Facility_for_the_Java_Programming_Language