Search code examples
common-lispmetaclassclos

Common Lisp Multiple Metaclasses


Having recently discovered an active fork of weblocks, I would like to combine it with the ORM library mito.

Weblocks defines a macro defwidget, which in practice wraps defclass like so:

(defclass my-class ()
  ((slot))
  (:metaclass weblocks/widgets/mop:widgets-class))

Meanwhile Mito works like so:

(defclass my-class ()
  ((...))
  (:metaclass mito:dao-table-class))

How can I make it so that the following works?

(defclass my-class ()
  (...))

(defvar *obj* (make-instance 'my-class))

(render *obj*) ;render from weblocks

(save-dao *obj*) ;save-dao from mito

(my-method *obj*)

I've tried inheritance, but failed in some different ways. I've only used CLOS a short time. Thus I have trouble gauging where on the spectrum

"I'm stupid <=====> This is impossible"

I am standing. Any help would be appreciated.


Solution

  • I've tried inheritance, but failed in some different ways. I've only used CLOS a short time. Thus I have trouble gauging where on the spectrum ...

    Don't worry, jumping straight to metaobjects with little experience with CLOS certainly is difficult, I recommend reading The Art of the Metaobject Protocol, (also known as "AMOP", by Gregor Kiczales and Jim Des Rivieres). There is an HTML version of chapters 5 and 6 by Robert Strandh at http://metamodular.com/CLOS-MOP.

    You want to define a hybrid metaclass, that inherits from both metaclasses.

    (defclass hybrid-metaclass (mito:dao-table-class
                                weblocks:widget-class)
      ())
    

    If you define a class with the above metaclass, you are going to have this warning:

    ;; WARNING: #<HYBRID-METACLASS COMMON-LISP-USER::MY-WIDGET {100B8FE683}> is not
    ;; defined to be a subclass of WEBLOCKS:WIDGET; consider adding WEBLOCKS:WIDGET
    ;; or a subclass thereof to the superclass list
    

    The widget-class metaclass expects all its classes to inherits from a base class, weblocks:widget.

    Let's define such a base object for our hybrid metaclass:

    (defclass hybrid-widget (weblocks:widget) ()
      (:metaclass hybrid-metaclass))
    

    Here, hybrid-widget inherits from weblocks:widget, and has for metaclass hybrid-metaclass. All your widgets should inherit from this class and have for metaclass hybrid-metaclass (feel free to find a better name).