Summary
Recent discussions on Artima focused on the merits of metaprogramming: writing programs that manipulate programs. One metaprogramming technique is to generate source code. In Java, one can use metaprogramming to generate bytecode as well, which is the subject of a recent article.
Advertisement
Metaprogramming is about writing programs that write programs, often as a way to improve productivity. A recent Artima discussion focused on the merits of metaprogramming in generating source code from a domain-specific language (DSL). Since a DSL can be compact and very focused on an application domain, generating an often more verbose program in a target language such as Java can not only save time, but also help create more consistent programs.
Java source code is usually compiled to an intermediate bytecode format, and metaprogramming techniques can be used to manipulate bytecode directly. Because Java bytecode is often more compact than source code, manipulating bytecodes directly can have the same benefits as source code-level metaprogramming with the bonus of speed, allowing metaprogramming to be used even at runtime. Such techniques are employed, for instance, by tools such as Hibernate or code coverage tools to instrument bytecodes loaded into the JVM.
Just as source-code generation from a DSL can lead to more flexible systems—since a DSL can be targetted to different languages and the DSL and generated source code can evolve independently—byte code generation and manipulation can bring about a similar benefit. For instance, bytecode can be examined and modified at runtime to suit a target environment of the deployed system. The authors of ASM, a popular bytecode manipulation library, summarize this benefit:
Most of the techniques used to implement dynamically adaptible systems use some form of interposition, [such as] interposition objects, meta objects, [etc.] Interposition can indeed be used not only to modify the semantics of components, for example to add [to] them functional or non-functional properties, but also to dynamically add and remove these [...] properties.
In a recent series of articles, Dennis Sosnoski explores bytecode-level metaprogramming and other ways of manipulting classes. He points out that throughout its evolution, the Java bytecode format has added an increasingly rich set of class metadata, generics being the latest and most comprehensive addition. Much of that information is there for developers to exploit via bytecode-level metaprogramming techniques, allowing the creation of more flexible systems.
Dennis' articles also point out that Java's reflection facility works only on classes already loaded into the JVM. Thus, reflection has limited benefits in the context of bytecode-level metaprogramming. Instead, he shows how to obtain and modify class data before loading classes into the JVM.
Have you used bytecode-level metaprogramming tools in your work? If so, did you find that generating or changing bytecodes on the fly leads to more adaptable systems?
Metaprogramming proves the power of functions: functions do not only allow to make computations, but also to make other functions.
Programming languages that depend on a VM could easily have metaprogramming in their list of capabilities. It is more difficult for compiled-to-native-code languages, but it is doable.