Re: Adding slots to an existing class definition
On 27 Jul 2005, at 06:55, Bob Hutchison wrote:
> Hi,
>
> Is there a standard way to add slot definitions to an existing class?
>
> I've appended a bit of code that is quite rigid but that
> successfully adds a second slot to an existing class. It is hard
> coded but illustrates the only technique I've managed to come up with.
>
> This can be generalised easily enough, but surely there is a better
> way. For one thing, this is definitely not going to work in at
> least some other implementations of CL.
Adding slots to an existing class can be achieved with the so-called
destructive mixins that are part of AspectL - see http://common-
lisp.net/project/aspectl/
Example: Assume you have a class person defined as follows.
(defclass person ()
((name :accessor name :initarg :name)))
At a later stage in the program, you can add new slots to such a
class, without repeating the complete class definition, as follows.
(with-class 'person
(class-add
:direct-slots
'(age :accessor age :initarg :age)))
The code is portable and runs on several Common Lisp implementations.
However, it's very easy to shoot yourself in the foot with
destructive mixins because I have added no checks whatsoever. So, for
example, if some of your slot options are incorrect, or you try to
override a slot from a superclass in some incompatible way, you will
probably not get an exception, but the chances are high that your
system will become just unusable and must be restarted.
I have stopped working on this further because I think I have found a
better, more declarative approach by now. ContextL is a new library
(that is going to supersede AspectL - I have basically thrown away
the AOP notions because they don't make much sense in Common Lisp, so
I had to find a new name... ;). Among the features of ContextL, there
are partial classes that allow you to spread class definitions into
different layers. The above example would look as follows in ContextL:
(defclass person ()
((name :accessor name :initarg :name))
(:metaclass partial-class))
(deflayer info-layer)
(defclass person ()
((age :accessor age :initarg :age))
(:metaclass partial-class)
(:in-layer info-layer))
The different partial definitions in the different layers contribute
to the same class, so here the class person will have both the name
and the age slots. You can even redefine the two partial classes
independently, so if you say this subsequently:
(defclass person ()
((employer :accessor employer :initarg :employer))
(:metaclass partial-class)
(:in-layer info-layer))
....the class will lose its age slot and gain an employer slot, but
the name slot will not be touched.
I think this is a better way to deal with "extra" slots. Especially,
it gives you all the safety nets that CLOS provides for preventing
bad class definitions.
ContextL is not publicly available yet. I expect to be able to make
it available in August or September the latest. The code runs on my
machine on seven different Common Lisp implementations, so I think
portability is not an issue. (The only thing holding me back from
uploading the code to some server right now is that I want to set up
a darcs repository and make the code asdf installable. Uploading new
versions of AspectL was always a little bit too much work for my
taste, and I want to avoid that for ContextL, so I would like to do
the right thing from the start this time.)
Pascal
--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/