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
.

- 136,269
- 10
- 221
- 346

- 319
- 2
- 6
2 Answers
Use Closer to Mop:
(defpackage :so (:use :closer-common-lisp))
(in-package :so)
;; Define a metaclass named json-class.
;; It inherits from a standard-class
(defclass json-class (standard-class) ())
Specialize VALIDATE-SUPERCLASS
(see also VALIDATE-SUPERCLASS explained).
(defmethod validate-superclass ((j json-class) (s standard-class)) t)
Then you define the base json-object
.
(defclass json-object () () (:metaclass json-class))
For example:
(class-of (make-instance 'json-object))
#<JSON-CLASS SO::JSON-OBJECT>
The returned object is a json-object
, an instance of json-class
, a subclass of standard-class
.

- 37,664
- 5
- 43
- 77
-
2So, if I understand correctly, if I then want to create a class with the `json-class` properties and I want it to inherit all the methods specialized for `json-object` I should define for example the class as `(defclass person (json-object) () (:metaclass json-class))` right? I also had an idea of using the `ensure-class-using-class` method to automatically add `json-object` to the `direct-superclasses` list but it does not look explicit to me. Would it be considered good design to just keep it explicit in the class definition? Or is there a better way to declare such a class? – MPaga Jul 26 '19 at 16:25
-
@MPaga: I think there ought to be an easy way to default the superclasses (after all, there is for instances of `standard-class`. But I can't work out what it should be. – Jul 27 '19 at 19:38
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.

- 12,292
- 8
- 41
- 69