[elephant-devel] Elephant and inheritance

Ian Eslick eslick at csail.mit.edu
Wed Oct 11 15:29:52 UTC 2006


Well it's a bit of a design trade off.

If you have a non-persistent base class, should the semantics of the
slot storage change based on whether it's included in a persistent
subclass?   Currently the policy is simple; persistence is determined by
annotations on direct slots and not effective slots.  Thus you can get
functional inheritance, but have to manually specify if you want to
persist an inherited non-persistent subclass.

To get persistent behavior for non-persistent base classes you need to
explicitly tell the CLOS protocol that a slot is persistent and the only
way to do that today is to include the base class slots directly in the
superclass.  You'll still get the base class generic function dispatch,
but reads/writes will go to the persistent store instead of memory.

(defclass foo ()
  ((myfoo)
   (bar)))

(defclass sub-foo (foo)
  ((bar)
   (baz))
  (:metaclass ele:persistent-metaclass))

Thus myfoo is transient and bar, baz are persistent.

(defmethod mutate-bar ((obj foo) value)
   (setf (slot-value obj 'bar) value))

This will set the persistent value of bar for objects of sub-foo, but
set the in-memory value of bar if the object is of type 'foo'.

It is possible to do this automatically by modifying the Elephant
metaclass protocol, perhaps with a class option or a new metaclass
'inheriting-persistent-metaclass' which defaults to making all subclass
slots persistent...then to override this behavior you'd special case
subclass slot names by specifying transient in a shadowing subclass
definition.

(defclass foo ()
   ((myfoo)
    (bar)))

(defclass sub-foo (foo)
   ((baz)
    (myfoo :transient t))
   (:persist-subclass-slots t)
   (:metaclass ele:persistent-metaclass))

This would have identical behavior to the first example, but you don't
have to make myfoo transient (it would then be given a persistent type
for sub-foo).

Now what happens if we inherit from sub-foo above?

(defclass sub-sub-foo (sub-foo)
   ((qux))
   (:metaclass ele:persistent-metaclass))  ;; protocol will assert an
error if subclass of persistent isn't persistent

In this case the normal CLOS machinery will pick up the non-direct slots
from subclasses and the bar and myfoo
slots will be non-transient.  There may be a way to override this to
search for subclass specifications of :persist-subclass-slots and then
go ahead and promote :transient effective slots to :persistent but all
the cases and interactions can start to become hairy.

I think the currently policy is the simplest and least bug prone, even
though it forces the increased verboseness of the first example.

Thoughts?

Ian


Pierre THIERRY wrote:
> I'm happily using Elephant in a Web-based project right now, but I'm
> getting annoyed by the behoviour of Elephant WRT inheritance. The
> problem is that only direct slots of the class with the persistent
> metaclass as metaclass are made persistent.
>
> If I have the following classes:
>
> (defclass foo ()
>   ((bar)))
>   
> (defclass sub-foo (foo)
>   ((baz))
>   (:metaclass ele:persistent-metaclass))
>   
> Only the baz slot will be persistent. Is it impossible to gain advantage
> of both inheritance and persistence, or am I missing something?
>
> Curiously,
> Nowhere man
>   
> ------------------------------------------------------------------------
>
> _______________________________________________
> elephant-devel site list
> elephant-devel at common-lisp.net
> http://common-lisp.net/mailman/listinfo/elephant-devel



More information about the elephant-devel mailing list