The essence of a Metaobject Protocol is simple: every aspect of a program's mapping down onto the lower level substrate (i.e. its compilation and runtime support) is controlled by some object or set of objects following a well-defined protocol. These objects are called metaobjects, because they are about the mapping of the program, rather than objects in the program's primary subject domain. Client programmers can replace one or more of these objects with specialized ones to affect specific aspects of the implementation of specific parts of their program.
Also see Andreas Paepcke, "User-Level Language Crafting": http://citeseer.ist.psu.edu/paepcke93userlevel.html
How about: make your interpreter (or compiler) available in your program, so that you can change rules for method lookup, variable scoping or whatever else you want in your program. This makes sense, sometimes -- for instance, a better stack tracer that elides calls to the standard library.
Let me take my stab, having (tried to) read the book:
-- HankRoark
Perhaps you can get more from an example. This link gives an implementation of an Eiffel inspired DesignByContract extension to the CommonLispObjectSystem. A number of the basic mechanism of the OO language are overridden and augmented to do class invariant checking, pre- and post-conditions etc.
http://www.muc.de/~hoelzl/tools/dbc/dbc.lisp
-- Lieven Marchand <mal@bewoner.dma.be>
At first glance, it might seem weird to change how something like method lookup works. But consider an analogy with something more pedestrian: overriding inherited methods. Sometimes you completely replace the superclass' implementation, but just as often you augment it.
This is why a metaobject protocol is of interest to people working on AspectOrientedProgramming. Without a MOP, aspects have to be implemented by weaving, which involves modifying the application source code. A MOP permits another strategy: extending the runtime object system to detect those situations when an aspect is applicable, and interpose the aspect's functionality. You still need a tool to interpret the aspects, but the tool is much simpler with a MOP. --GlennVanderburg
I would include not just "every aspect" nor even "most basic constructs" but anything at the virtual machine level. For example, if you can control your memory manager by switching garbage collection on and off, requesting a collection, explicitly freeing objects etc, I'd call that a MOP. -- DaveHarris
I'm not sure I would. It's a Meta Object Protocol, and garbage collection seems more low level and wider in scope than that (in other words those effects are system wide, not really [replacing] one or more of these objects with specialized ones to affect specific aspects of the implementation of specific parts of their program. )
-- PaulHudsonDave, the people at Xerox who like to talk about this stuff a lot (I don't know whether they're responsible for it or not, but they sure do like to talk about it :-) treat a MOP as a special case of a more general concept: OpenImplementation. I think what you're talking about fits in the more general space. --GlennVanderburg
Maybe. I was thinking the garbage collector was an object in its own right, belonging to the meta level, and accessed through a protocol, so meta object protocol seemed to fit. Consider allocators in C++. Probably I'm wrong, but I'll leave the discussion in case it helps someone else. -- DaveHarris
No, you were thinking that "anything at the virtual machine level" is MOP; GC was just an "example". Even if you're right about GC, Glenn's comment about "a more general concept" fits the bill.
Excerpt from TheArtOfTheMetaObjectProtocol
http://www.parc.xerox.com/spl/projects/mops/default.html [BrokenLink -- 2006-08-16]
http://www.elwood.com/alu/mop/index.html [BrokenLink -- 2006-08-16]
PattieMaes has written some wonderful papers about this topic.
My view is that a Metaobject Protocol is a fundamentally important attribute of a CausallyReflectiveSystem?. These systems virtually always have the ability to treat at least some memory as both code and data. In a Unix environment, this amounts to being able to execute from the data segment or write to the code segment, or both.
An application written, naively, in C or C++ and running on Unix is typically NotReflective?. The application has very limited or no ability to perform computations on itself. For example, its current process state or variable bindings are not accessible to it.
Some systems are DescriptivelyReflective?. Early examples of this were the C++-based object databases, such as ObjectStore and Ontos. A DescriptivelyReflective? system contains a description of itself, and may even use that description, but changing that description merely breaks the system.
The category of systems that I find interesting are CausallyReflective? systems, such as CommonLisp and Smalltalk. A CausallyReflective? system is written in terms of itself. It contains a description of its own behavior, and uses that description to control its behavior, so that a change to that description changes its behavior.
I suspect that an enterprising PhD candidate could, if it has not already been done, write a thesis proving the hypothesis that a CausallyReflective? system must have a metaobject protocol.
-- TomStambaugh
MOP and causal reflectivity are rather obviously orthogonal -- causally reflective systems need not expose their descriptions or allow them to be modified, and the descriptions of non-reflective systems can be exposed and modified. And if all you mean is that a causally reflective system necessarily has a description that can be formalized as a data object that the system can interpret -- well, that's how it was just defined, so it wouldn't take a PhD thesis to demonstrate it.
Another source of information on MetaClass programming and Meta Object Protocols is the book "Putting Metaclasses to Work". They even have some simulation code (written in Java) showing their MOP at work (located at http://www.amazon.com/exec/obidos/tg/detail/-/0201433052).
A metaobject protocol certainly seems powerful. An obvious example would be (I guess) C++ operator overloading, where you can define what otherwise ordinary language elements do to a particular class. Or the java.lang.reflect package in Java, where you can do computation on the structure of your program. (For example, some cool self-configuring systems like JavaBeans work by scanning the names of your class's methods for particular naming conventions.)
Operator overloading is no different from overloading any other method name -- it has nothing to do with MOP. Nor does introspection.
But these sorts of features and capabilities are the enemy of learnable, ReadableCode, and I find that they are rarely used judiciously. -- RusHeywood
Well, one example where MOP is often used is to provide persistency. See for example PLOB! (persistent lisp objects) or the DEF-VIEW-CLASS macro provided with Xanaly's lisp. Both these systems let you create CLOS objects whose metaclass is not STANDARD-CLASS, but rather a new, persistent class. The degree of integration into "normal lisp" provided by these tools is simply astounding. I would call that a judicious use indeed. All extremely powerful tools, (and is MOP ever one!) require extreme care and competence by the craftsman.
See also: AccessorEvents, AdvantagesOfExposingRunTimeEngine, OneMoreLevelOfIndirection