Next: Support For Unix, Previous: Garbage Collection, Up: Beyond the ANSI Standard

### 7.2 Metaobject Protocol

SBCL supports a metaobject protocol which is intended to be compatible with AMOP; present exceptions to this (as distinct from current bugs) are:

- `compute-effective-method` only returns one value, not two.

  There is no record of what the second return value was meant to indicate, and apparently no clients for it.

- The direct superclasses of `sb-mop:funcallable-standard-object` are `(function standard-object)`, not `(standard-object function)`.

  This is to ensure that the `standard-object` class is the last of the standardized classes before `t` appearing in the class precedence list of `generic-function` and `standard-generic-function`, as required by section 1.4.4.5 of the ANSI specification.

- the arguments `:declare` and `:declarations` to `ensure-generic-function` are both accepted, with the leftmost argument defining the declarations to be stored and returned by `generic-function-declarations`.

  Where AMOP specifies `:declarations` as the keyword argument to `ensure-generic-function`, the Common Lisp standard specifies `:declare`. Portable code should use `:declare`.

- although SBCL obeys the requirement in AMOP that `validate-superclass` should treat `standard-class` and `funcallable-standard-class` as compatible metaclasses, we impose an additional requirement at class finalization time: a class of metaclass `funcallable-standard-class` must have `function` in its superclasses, and a class of metaclass `standard-class` must not.

  After a class has been finalized, it is associated with a class prototype which is accessible by a standard mop function `sb-mop:class-prototype`. The user can then ask whether this object is a `function` or not in several different ways: whether it is a function according to `typep`; whether its `class-of` is `subtypep` `function`, or whether `function` appears in the superclasses of the class. The additional consistency requirement comes from the desire to make all of these answers the same.

  The following class definitions are bad, and will lead to errors either immediately or if an instance is created:

                (defclass bad-object (funcallable-standard-object)
                  ()
                  (:metaclass standard-class))

                (defclass bad-funcallable-object (standard-object)
                  ()
                  (:metaclass funcallable-standard-class))

  The following definition is acceptable:

                (defclass mixin ()
                  ((slot :initarg slot)))
                (defclass funcallable-object (funcallable-standard-object mixin)
                  ()
                  (:metaclass funcallable-standard-class))

  and leads to a class whose instances are funcallable and have one slot.

  Note that this requirement also applies to the class `sb-mop:funcallable-standard-object`, which has metaclass `sb-mop:funcallable-standard-class` rather than `standard-class` as AMOP specifies.

- the requirement that “No portable class C_p may inherit, by virtue of being a direct or indirect subclass of a specified class, any slot for which the name is a symbol accessible in the `common-lisp-user` package or exported by any package defined in the ANSI Common Lisp standard.” is interpreted to mean that the standardized classes themselves should not have slots named by external symbols of public packages.

  The rationale behind the restriction is likely to be similar to the ANSI Common Lisp restriction on defining functions, variables and types named by symbols in the Common Lisp package: preventing two independent pieces of software from colliding with each other.

- specializations of the `new-value` argument to `(setf sb-mop:slot-value-using-class)` are not allowed: all user-defined methods must have a specializer of the class `t`.

  This prohibition is motivated by a separation of layers: the `slot-value-using-class` family of functions is intended for use in implementing different and new slot allocation strategies, rather than in performing application-level dispatching. Additionally, with this requirement, there is a one-to-one mapping between metaclass, class and slot-definition-class tuples and effective methods of `(setf slot-value-using-class)`, which permits optimization of `(setf slot-value-using-class)`'s discriminating function in the same manner as for `slot-value-using-class` and `slot-boundp-using-class`.

  Note that application code may specialize on the `new-value` argument of slot accessors.

- the class named by the `name` argument to `ensure-class`, if any, is only redefined if it is the proper name of that class; otherwise, a new class is created.

  This is consistent with the description of `ensure-class` in AMOP as the functional version of `defclass`, which has this behaviour; however, it is not consistent with the weaker requirement in AMOP, which states that any class found by `find-class`, no matter what its `class-name`, is redefined.

In addition, SBCL supports extensions to the Metaobject protocol from AMOP; at present, they are:

- compile-time support for generating specializer metaobjects from specializer names in `defmethod` forms is provided by the `make-method-specializers-form` function, which returns a form which, when evaluated in the lexical environment of the `defmethod`, returns a list of specializer metaobjects. This operator suffers from similar restrictions to those affecting `make-method-lambda`, namely that the generic function must be defined when the `defmethod` form is expanded, so that the correct method of `make-method-specializers-form` is invoked. The system-provided method on `make-method-specializers-form` generates a call to `find-class` for each symbol specializer name, and a call to `intern-eql-specializer` for each `(eql` x`)` specializer name.
- run-time support for converting between specializer names and specializer metaobjects, mostly for the purposes of `find-method`, is provided by `parse-specializer-using-class` and `unparse-specializer-using-class`, which dispatch on their first argument, the generic function associated with a method with the given specializer. The system-provided methods on those methods convert between classes and proper names and between lists of the form `(eql` x`)` and interned eql specializer objects.