The Art of the Metaobject Protocol (AMOP) is a 1991 book by Gregor Kiczales, Jim des Rivieres, and Daniel G. Bobrow (all three working for Xerox PARC) on the subject of metaobject protocol.
The book contains an explanation of what a metaobject protocol is, why it is desirable, and the de facto standard for the metaobject protocol supported by many Common Lisp implementations as an extension of the Common Lisp Object System, or CLOS. A more complete and portable implementation of CLOS and the metaobject protocol, as defined in this book, was provided by Xerox PARC as Portable Common Loops.
The book presents a simplified CLOS implementation for Common Lisp called \"Closette\", which for the sake of pedagogical brevity does not include some of the more complex or exotic CLOS features such as forward-referencing of superclasses, full class and method redefinitions, advanced user-defined method combinations, and complete integration of CLOS classes with Common Lisp's type system. It also lacks support for compilation and most error checking, since the purpose of Closette is not actual use, but simply to demonstrate the fundamental power and expressive flexibility of metaobject protocols as an application of the principles of the meta-circular evaluator.
The basic idea of a metaobject protocol is to implement an object system using its own constructs as building blocks. The fundamental constructs available to application programmers, such as classes, generic functions and methods, are themselves instances of (meta)classes. While the resulting design is remarkably consistent and clean, the big win is that a metaobject provides an extremely powerful extension mechanism. The metaobject protocol behaves like an interface towards the language itself, available for the programmer to incrementally customize. Just as we can specialize and extend the behavior of the classes we define in our own applications, we can now extend the language itself using the very same mechanisms. It's a design resulting from the direct conclusion that no language will be universally appropriate for all problems. Instead of fighting the language, the programmer adapts and evolves it to the problem at hand. The Art of the Metaobject Protocol (AMOP) is a wonderful book to learn about these topics.
A metaobject protocol gives application programmers an interesting context. With a metaobject protocol the available design space isn't fixed. Rather the possible design space extends to a larger region. This region is defined by the extension points in the metaobject protocol. To give an example, say we want to change some aspect of object allocation. Or perhaps we want to change the dispatch rules for a set of types. The practical purpose could be to balance the classical trade-off between speed and memory or, more radically, provide a completely different storage mechanism for our objects (e.g. in a distributed key value store). With a metaobject protocol, such fundamental changes to the language are only a few specializations away. The beauty is that we implement it using the very same mechanisms we'd use for traditional object-oriented programming with CLOS. As such, AMOP presents an approach to language design that is radically different from what we've come to know in popular object-oriented languages of today.
Designing an object system based on a metaobject protocol is an old and mature idea by now. Yet the idea is conceptually challenging. For once, how do you start The consequence of a metacircular object protocol is that initial metaobjects will have to be instances of themselves. Clearly, we can't have full-featured CLOS objects all the way down; at some point they need to rest firmly on a turtle. I was delighted to see that AMOP covers these decisions and bootstrapping strategies as well. Basically, the typical bootstrapping approach is to hand-code the initial metaobjects. This strategy rests on the assumption that we only need a minimum set of fundamental metaobjects with known slot-values up-front. The challenge, as AMOP puts it, is to create these initial metaobjects with as little effort as possible.
The book serves two purposes. First, it's mandatory reading if you want to dig deep into CLOS and unleash the power of its metaobject protocol. AMOP is the definitive guide here. The only remark I have is that while AMOP provides a complete discussion on the implementation of the protocol itself, it's quite weak on possible applications and use cases. In practice this is less of a problem. Today there are several open-source libraries that extend CLOS through its metaobject protocol. For example, the elegant Elephant library uses the metaobject protocol to provide simple persistent objects. I'd recommend the Elephant source code as a useful reading companion to this book.
The authors introduce this new approach to programming language design, describe its evolution and design principles, and present a formal specification of a metaobject protocol for CLOS.
The CLOS metaobject protocol is an elegant, high-performance extension to the CommonLisp Object System. The authors, who developed the metaobject protocol and who were among the group that developed CLOS, introduce this new approach to programming language design, describe its evolution and design principles, and present a formal specification of a metaobject protocol for CLOS.
Kiczales, des Rivières, and Bobrow show that the \"art of metaobject protocol design\" lies in creating a synthetic combination of object-oriented and reflective techniques that can be applied under existing software engineering considerations to yield a new approach to programming language design that meets a broad set of design criteria.
One of the major benefits of including the metaobject protocol in programming languages is that it allows users to adjust the language to better suit their needs. Metaobject protocols also disprove the adage that adding more flexibility to a programming language reduces its performance. In presenting the principles of metaobject protocols, the authors work with actual code for a simplified implementation of CLOS and its metaobject protocol, providing an opportunity for the reader to gain hands-on experience with the design process. They also include a number of exercises that address important concerns and open issues.
I've read about 60 pages and a question came to my mind:Authors talk about dynamic class creation, inspectingclasses at runtime, etc. How are these features comparedto \"reflection\" in Java, C#, etc I don't know muchabout that but as far as I know Java and C# programmerscan also introspect classes during runtime, create classeson-the-fly, etc. which they call the \"reflection\" propertyof their language, rightIs MetaObject protocol for CLOS similar to \"reflection\"in those languages Is it something more, something lessHas some advantages that reflection in Java and C# don'thaveMaybe the masters well versed in both languages can enlightenme.Thanks in advance.Happy hacking.-- Emre SevinceMBA Software Developer Actively engaged in:http:www.bilgi.edu.tr Cognitive Science Student
Reflection originally means both introspection and intercession (these are the technical terms). Introspection allows you to find out information about elements of your program - classes, variables, methods, functions, etc. What the Java folks called reflection in the beginning is indeed just introspection.Intercession is a way to modify the characteristics of the elements of your program. So intercession allows you to change the properties of classes, variables, methods, functions, etc.Reflection was originally \"invented\" by Brian Smith in the form of procedural reflection - i.e., you basically have a notion of interceding procedure calls, inspecting the environment(s) that are active during those calls, and possibly changing the way the program continues its execution. If you allow programmers to intercede at each and every single step of your program execution, though, your programs slow down considerably, even if noone intercedes anything, because the runtime has to continually check whether someone wants to do something additionally or not.For that reason, Brian Smith and Jim des Rivieres (if I understand correctly, it was those two guys) implemented reflection by dividing the program into levels, so that one could specify at which level you want to intercede the program execution. The levels for which you don't intercede can be executed \"at full speed\", while the other levels have to run your additional code.It was then discovered that this actually leads to an object-oriented design of the reflection facilities, because the notion of dividing programs into levels and specifying different behavior at different levels is more or less exactly what you do in an object-oriented hierarchy. So, for example, in a class hierarchy, the classes higher up in the hierarchy define the \"base\" behavior while the classes that inherit from those superclasses define the additional behavior. Next, when you disallow programmers from changing the definitions of the base classes, you can actually implement the runtime much more efficiently because you can check whether a given object is an instance of a base class or not, and if it's an instance of a base class you can run optimized versions of the methods defined on those classes that don't call the (non-existent) code of subclasses.The CLOS Metaobject Protocol is essentially that idea carried through the end.Java reflection is not even close. Java has meta-level objects that describe classes, methods, fields, etc., but there is no way to change them. However, there are some little opportunities to get something along the lines of a full-blown metaobject protocol:- You can implement proxy classes - see java.lang.reflect.InvocationHandler. This allows you to intercept method calls to objects.- There is a debugging API that allows you to change the definition of a class (including its methods) at runtime, which in principle allows you to add additional behavior to methods.- Finally, you can intercept class loading and modify the bytecode for a class before it enters the virtual machine. This is the most powerful way to achieve similar effects as those of a MOP, but is not a proper MOP in its own right. (You don't specify the new behavior as methods for meta-level classes, but you rather just modify a byte stream.)The latter has been used to define proper (load-time) metaobject protocols, though, for example Javassist and Reflex.These things are much more complicated to achieve in Java than in CLOS, though, even with such frameworks. Furthermore, I am convinced that a full runtime metaobject protocol is essential. (Load-time or compile-time metaobject protocol can lead to more efficient code, that's why they have been pursued in the past, but I think these efficiency gains are too small to be important enough in the long run. The flexibility of a runtime metaobject protocal is more important because it gives you more expressivity IMHO.)I think the situation for C# is similar to that for Java, although they have added a few more practical stuff from the beginning. For example, .NET comes with a library that gives you a (modifiable) representation of their bytecode format, and I recall seeing a presentation about a load-time bytecode modification approach for .NET that was a lot simpler than what I have seen in the Java world. But that's all I can tell about C#.Metaobject protocols exist for other languages (and also for other domains than language implementations). A relatively old list of metaobject protocols is given at -mops.htmlEric Tanter provides an excellent and recent overview of reflection, metaobject protocols and aspect-oriented programming (which is another form of reflection, in a sense) in his PhD thesis about Reflex - see etanter/Pascal-- OOPSLA'05 tutorial on generic functions & the CLOS Metaobject Protocol++++ see -cos.net/oopsla05-tutorial.html for more details ++++ 153554b96e