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:
- The core of the Metaobject Protocol is to replace the most basic constructs of a language (in the case of OO languages, this would consist of things like how polymorphism is defined, how to treat inheritance (multiple and single), etc.) and make them so they can be configured and changed.
From what I recall, this was important to the implementers of the CommonLispObjectSystem
because they wanted to maintain backwards compatibility with many Lisp implementations, each of which had its own rules regarding inheritance, etc.
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.
-- Lieven Marchand <email@example.com>
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
This is why a metaobject protocol is of interest to people working on
. Without a MOP, aspects have to be implemented
, 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.
Dave, 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:
. 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
- In a language based upon [our] metaobject protocols, the language implementation itself is structured as an object-oriented program. This allows us to exploit the power of object-oriented programming techniques to to make the language implementation adjustable and flexible. In effect, the resulting implementation does not represent a single point in the overall space of language designs, but an entire region within that space.
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.
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.
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.