Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 701
otyn Avatar asked Dec 09 '18 16:12

otyn


2 Answers

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).

like image 84
coredump Avatar answered Sep 19 '22 07:09

coredump


Even if it is possible to solve as @coredump suggests, I don't recommend you to mix model (storage and business logic) and widget (representation of these objects) in one class.

Usually, I define my widget with a slot pointing to an object. This way, you can also define widgets which contain lists of objects. It is useful when making a widget for each separate object don't have a sense.

You only need to make 1-1 link between object and widget when you need to update an object's representation separately from other blocks as a response to some action, for example on marking a task as DONE.

like image 41
Alexander Artemenko Avatar answered Sep 19 '22 07:09

Alexander Artemenko