lispcommon-lispclosmop

How to make the instances of a class using a metaclass inherit from a specific superclass


I'm trying to implement json serialization API for common lisp. To achieve this I've defined a metaclass called json-class. This metaclass defines the slot options :ignore which are used to ignore specific slots of the object. Since I'm using yason for the serialization process, I wanted to specialize the method yason:encode-slots to every object of classes that use the metaclass json-class. The only way I can think of to achieve this, is to make all the objects instantiated from a json-class of type json-object which can be used to specialize the methods. The behaviour that I'm trying to replicate is the same as the one already implemented by the MOP consisting in every class using the standard-class producing an object of type standard-object.


Solution

  • If you look through the source code of SBCL, you'll find that it adds standard-object to the list of direct superclasses inside of shared-initialize:

             (setq direct-superclasses
                   (or direct-superclasses
                       (list (if (funcallable-standard-class-p class)
                                 *the-class-funcallable-standard-object*
                                 *the-class-standard-object*))))
    
    

    If you wish to implicitly add a class to the direct superclasses list, it may be best to do so in an :around method on shared-initialize or initialize-instance.

    Another option is to specialize compute-class-precedence-list to, for example:

    (cons my-superclass (call-next-method))

    This is what An existing JSON MOP library does.

    EDIT:

    I think messing with compute-class-precedence-list to add superclasses is undefined behavior, though it usually works. I believe the best solution is to write an :around method for either shared-initialize or initialize-instance that first checks (using subclassp) whether your class is already in the inheritance chain, then adds it if not.