From: Pascal Costanza Newsgroups: comp.lang.lisp Subject: Re: Art of MetaObject Protocol and Reflection (Java, C#, etc.) Date: Sun, 18 Sep 2005 15:06:57 +0200 Lines: 114 Message-ID: <3p573iF8lvf2U1@individual.net> References: <87slw2wted.fsf@ileriseviye.org> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Trace: individual.net BtB6JRtZRY+d/AVQvMK4tQYXPICHQocOqxprpIqueYmCP8DnBI In-Reply-To: <87slw2wted.fsf@ileriseviye.org> Xref: reader0.news.be.easynet.net comp.lang.lisp:103711 Emre Sevinc wrote: > I'm reading The Art of MetaObject Protocol and try to > understand how it extends CLOS. > > I've read about 60 pages and a question came to my mind: > > Authors talk about dynamic class creation, inspecting > classes at runtime, etc. How are these features compared > to "reflection" in Java, C#, etc? I don't know much > about that but as far as I know Java and C# programmers > can also introspect classes during runtime, create classes > on-the-fly, etc. which they call the "reflection" property > of their language, right? > > Is MetaObject protocol for CLOS similar to "reflection" > in those languages? Is it something more, something less? > Has some advantages that reflection in Java and C# don't > have? 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 http://www2.parc.com/csl/groups/sda/projects/mops/existing-mops.html Eric 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 http://www.dcc.uchile.cl/~etanter/ Pascal