Documentation: Hints for using the PCL Metaobject Protocol

The CLOS Metaobject Protocol (MOP) is a semi-standardized reflective extension to CLOS. Most Common Lisp implementations (including CMUCL) implement a metaobject protocol that is similar to the specification given in chapters 5 and 6 of the The Art of the MetaObject Protocol (a book whose title is often abbreviated AMOP). However, the PCL MOP provided by CMUCL has a few differences from AMOP, and behaves differently from the MOP in other Common Lisp implementations in certain respects.

The major issues that can arise are:

  • Make sure that you use symbols from the right package. A number of symbols, such as STANDARD-CLASS exist both in the COMMON-LISP package and in the PCL package. For MOP programming you should be using the symbols from the PCL package.
  • CMUCL has a package named MOP, which exports most (but not all) of the symbols defined in AMOP.
  • Since CMUCL uses special wrappers around class-objects, you sometimes need to use PCL::COERCE-TO-PCL-CLASS to coerce the wrapper objects into real MOP-aware objects. For example, this occurs when using the CLASS-OF function.
  • You may need to define methods on PCL:VALIDATE-SUPERCLASS more often than is said in AMOP. For example, consider a class called FOO whose metaclass is META-FOO. Class FOO inherits from class T, whose metaclass is STANDARD-CLASS, and in the PCL MOP you have to declare that this combination of metaclasses is valid:
       (defmethod pcl:validate-superclass ((class meta-foo) (super pcl::standard-class))

Details on the class schizophrenia

PCL, the CLOS implementation that is used in CMUCL, is integrated with the rest of CMUCL in a somewhat incomplete way. The type system of PCL and of the CMUCL kernel have different notions of what a class is. This is because classes are fundamental to the CMUCL type system, yet CMUCL needs to be able to function without PCL loaded (mainly in order to be able to build itself). The way that this problem is resolved is by having the CMUCL kernel maintain parallel class hierarchies. For instance, LISP:CLASS and PCL:CLASS are different types. The function LISP:FIND-CLASS returns instances of LISP:CLASS, whereas the function PCL:FIND-CLASS returns PCL:CLASS instances. For example

   USER> (lisp:find-class 'cons)
   #<built-in-class cons (sealed) {28073C8D}>
   USER> (pcl:find-class 'cons)
   #<Built-In-Class cons {2817967D}>

These two classes are in one sense the same class, in that they represent the same type: CONS. However, PCL has its own way of representing that type internally.

In order to make this situation livable, PCL has been hacked up to accept LISP:CLASS objects in the common places where people supply classes to PCL operations. You can also explicitly convert between the two kinds of classes, either by using the class name and the appropriate FIND-CLASS, or by:

    (kernel:class-pcl-class lisp-class)  ==> the PCL class
    (kernel:layout-class (pcl::class-wrapper pcl-class))  ==> the LISP class

Another problem area is with generic functions that are called by PCL with classes as arguments. These classes will be PCL:CLASSes, so if you try to specialize on e.g. ALLOCATE-INSTANCE using an EQL specializer, then make sure the class in the specializer is a PCL:CLASS.

People who stick to using standard CLOS operations shouldn't ever notice all this smoke and mirrors. People using standard CLOS operations shouldn't have their packages use the PCL package, since the Common-Lisp package exports a consistent set of definitions for standard CLOS operations.

Though the above hacks usually work for simple stuff, they often seem to break down when defining new metaclasses. What you need to do is explictly specify the PCL:: prefix on the class name.

Printable version of this page

Valid HTML 4.0 Transitional

Last modified 2019-09-28 by <webmaster@cmucl.cons.org>
Copyright © 1999-2019 CMUCL Project
Validate links, HTML, stylesheet.