I have been reading about the libraries people have written for languages like Java and C# that make use of byte code weaving to do things like intercept function calls, insert logging code, etc. I have also been reading up on Lisp/Clojure macros in an attempt to better understand how to utilize them. The more I read about macros, the more it seems like they provide the same kind of functionality as byte code weaving libraries. By functionality, I mean the ability to manipulate code at compile time.
Examples of libraries I have been looking at would be AspectJ, PostSharp, and Cecil.
Is there anything that can be done with one and not the other? Do they actually solve the same problems or am I comparing apples and oranges?
2
Byte code weaving and macros are two different things.
Byte code weaving is a way to intercept function calls, so that you can inject some sort of functionality (generally a cross-cutting concern such as logging) into a function call, either before or after the function is executed. Byte code weaving is done at the byte code level, which means that it occurs after compilation. The function itself is not affected. This is one of the techniques that Aspect Oriented Programming uses.
Macros are a way to extend the syntax of a language. In its simplest form, a macro is simply a way to record keystrokes, and then play them back using a hot key. Language macros work in a similar fashion; a keyword or other syntax construct substitutes for some sort of macro expansion. This is oversimplified, of course; a better example of a macro specific to Lisp can be found here.
6
Although they may be used to the same end, LISP macros are quite different from Java byte-code weaving plugins. LISP macros extend LISP syntax at the LISP source code level. Since LISP macros are written at the same level as other LISP code, they are a commonly used language feature.
Java byte-code weaving plugins operate at the JVM level. While many Java programmers may use byte-code weaving plugins written by others, very few Java programmers write their own byte-code weaving plugins.
Some of the work done by Java compiler plugins is very easily done in dynamic languages. Function-call interception is particularly simple.
2
Lisp macros are operating at the source code level. If you wrap some macro around a piece of code, then you can do a lot of things. Including parsing the source code, inserting code, rewriting code, etc.
If you want to modify function calls, Lisp usually uses two mechanisms:
-
late binding symbols. You can modify the function bound to a symbol. Every function calling which goes through a symbol, then uses the new function.
-
Lisp implementations sometimes provide a feature called ‘advice’. This allows to execute code before, after or around calls. For example in LispWorks: Advice.
Thus you can intercept calls without low-level code manipulation.