Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Programmatically adding a slot to a class

348 views
Skip to first unread message

Scott L. Burson

unread,
Jun 27, 2010, 7:00:11 PM6/27/10
to
For those with more MOP experience than I, what's the easiest way to
programmatically add a slot to an existing class?

-- Scott

Pascal J. Bourguignon

unread,
Jun 27, 2010, 7:31:06 PM6/27/10
to
"Scott L. Burson" <gy...@zeta-soft.com> writes:

> For those with more MOP experience than I, what's the easiest way to
> programmatically add a slot to an existing class?

mop:ensure-class.

Yes, you have to recreate the whole class.

You can also do it portably, with (eval `(defclass ...)).


Here is how I do it using ensure-class. The function
ENSURE-CLASS-SLOT adds a slot with slot options adequate for my
application:

(defun convert-to-direct-slot-definition (class canonicalized-slot)
(apply (function make-instance)
(apply (function clos:direct-slot-definition-class) class canonicalized-slot)
canonicalized-slot))


(defun canonicalize-slot-definition (slotdef)
(list :name (CLOS:SLOT-DEFINITION-NAME slotdef)
:readers (CLOS:SLOT-DEFINITION-READERS slotdef)
:writers (CLOS:SLOT-DEFINITION-WRITERS slotdef)
:type (CLOS:SLOT-DEFINITION-TYPE slotdef)
:allocation (CLOS:SLOT-DEFINITION-ALLOCATION slotdef)
:initargs (CLOS:SLOT-DEFINITION-INITARGS slotdef)
:initform (CLOS:SLOT-DEFINITION-INITFORM slotdef)
:initfunction (CLOS:SLOT-DEFINITION-INITFUNCTION slotdef)))


(defun ensure-class-slot (class-name slot-name)
(let ((class (find-class class-name)))
(when class
;; finalize it before calling CLOS:CLASS-SLOTS
(make-instance class-name)
(unless (find slot-name (clos:class-slots class)
:key (function clos:slot-definition-name))
(clos:ensure-class
class-name
:direct-slots
(append (mapcar (function canonicalize-slot-definition) (CLOS:CLASS-DIRECT-SLOTS class))
(list (list :name slot-name
:initform 'nil
:initfunction (constantly nil)
:initargs (list (intern (string slot-name) "KEYWORD"))
:readers (list slot-name)
:writers (list `(setf ,slot-name))
:documentation "Generated by define-association"))))))
class))

--
__Pascal Bourguignon__ http://www.informatimago.com/

Scott L. Burson

unread,
Jun 27, 2010, 7:42:34 PM6/27/10
to
On Jun 27, 4:31 pm, p...@informatimago.com (Pascal J. Bourguignon)
wrote:

> "Scott L. Burson" <g...@zeta-soft.com> writes:
>
> > For those with more MOP experience than I, what's the easiest way to
> > programmatically add a slot to an existing class?
>
> mop:ensure-class.
>
> Yes, you have to recreate the whole class.
>
> You can also do it portably, with (eval `(defclass ...)).
>
> Here is how I do it using ensure-class. [...]

Thanks! Hmm, I was hoping one didn't have to recreate the whole
class. But this should work anyway.

-- Scott

Scott L. Burson

unread,
Jun 27, 2010, 7:51:34 PM6/27/10
to

Now that I actually look at your code, I'm not sure what you mean by
"recreate the whole class". I thought you meant that ENSURE-CLASS
needed all the various arguments -- the same ones it would get if
being called by DEFCLASS to initially create the class. But I see
that's not the case.

Too bad the functionality of CANONICALIZE-SLOT-DEFINITION doesn't
happen automatically.

Oh, and I see that CONVERT-TO-DIRECT-SLOT-DEFINITION isn't actually
used here.

-- Scott

Pascal J. Bourguignon

unread,
Jun 27, 2010, 9:14:25 PM6/27/10
to
"Scott L. Burson" <gy...@zeta-soft.com> writes:

> On Jun 27, 4:42 pm, "Scott L. Burson" <g...@zeta-soft.com> wrote:
>> On Jun 27, 4:31 pm, p...@informatimago.com (Pascal J. Bourguignon)
>> wrote:
>>
>> > "Scott L. Burson" <g...@zeta-soft.com> writes:
>>
>> > > For those with more MOP experience than I, what's the easiest way to
>> > > programmatically add a slot to an existing class?
>>
>> > mop:ensure-class.
>>
>> > Yes, you have to recreate the whole class.
>>
>> > You can also do it portably, with (eval `(defclass ...)).
>>
>> > Here is how I do it using ensure-class. [...]
>>
>> Thanks!  Hmm, I was hoping one didn't have to recreate the whole
>> class.  But this should work anyway.
>
> Now that I actually look at your code, I'm not sure what you mean by
> "recreate the whole class". I thought you meant that ENSURE-CLASS
> needed all the various arguments -- the same ones it would get if
> being called by DEFCLASS to initially create the class. But I see
> that's not the case.

Yes, the only others are the superclasses, the meta-class and the
default-initargs. I assume the superclasses are not modified when we
use ENSURE-CLASS instead of ENSURE-CLASS-USING-CLASS. For the
default-initargs and the meta-class, I don't know, my classes don't
have any. (The documentation would be set separately with (setf
documentation)).


> Too bad the functionality of CANONICALIZE-SLOT-DEFINITION doesn't
> happen automatically.
>
> Oh, and I see that CONVERT-TO-DIRECT-SLOT-DEFINITION isn't actually
> used here.

Good. Better to have unused code, than missing code :-)

Pascal Costanza

unread,
Jun 28, 2010, 3:09:10 AM6/28/10
to
On 28/06/2010 01:00, Scott L. Burson wrote:
> For those with more MOP experience than I, what's the easiest way to
> programmatically add a slot to an existing class?

The situations were you may want to do this are usually extremely rare.
So it may be useful to tell us what you want to achieve, so we can maybe
come up with better solutions.


Pascal

--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/

jos...@lisp.de

unread,
Jun 28, 2010, 5:38:40 AM6/28/10
to
On 28 Jun., 09:09, Pascal Costanza <p...@p-cos.net> wrote:
> On 28/06/2010 01:00, Scott L. Burson wrote:
>
> > For those with more MOP experience than I, what's the easiest way to
> > programmatically add a slot to an existing class?
>
> The situations were you may want to do this are usually extremely rare.
> So it may be useful to tell us what you want to achieve, so we can maybe
> come up with better solutions.
>

I don't find that rare at all and would hope that adding a slot would
be be simpler.

That's one of the areas where other object-oriented systems for Lisp
were much easier to use.
For example in Object Lisp one could write nice tools to edit objects
graphically
and add/remove slots in a simple way. Every GUI based editor of a
class hierarchy
wants to manipulate slots. For example in a CAD system where classes
describe
objects, one may want to edit the classes in a browser. In an
interface designer,
the triangle-button-class may need another slot.

Lisp was developed with a focus on interactive development and over
time developers used
it to create interactive GUI based applications. A reason that this
tradition has been not revived as it should, in that CLOS is very
dynamic, but it makes some operations a bit difficult (like dealing
with slot information, adding slots, etc.). Garnet used a simple
frame system, Sk8 too, the early user interface designer for MCL
used a nice view system with prototype objects, ...

Another domain where this is heavily used is knowledge representation.
CLOS could have been used more widely here. As much as I like CLOS,
I think it lost some of the appeal of the earlier systesm -
probably because it was less driven by applications and practicality
, but slightly more
by abstract design considerations.

The effect is that editing text based Lisp is easy, but for creating
tools, one
has to go through more complex code than one may want.

Am I a dinosaur with my wish for easy to use tools for interactive
computation?
Is that out of fashion forever? Maybe I am spoiled by tools
that nobody anymore uses?

I guess somebody should demo things like Coral Common Lisp 1.0
on a Mac SE/30 at some Lisp user conference to give others
a feeling what was possible in Lisp with 2.5 MB of RAM
on a 68030. I know the workd has moved on, but it would be nice
if we have added capabilities and not lost them.

Pascal Costanza

unread,
Jun 28, 2010, 8:47:34 AM6/28/10
to

I haven't been around when all these things happened, so I have my
knowledge only from indirect sources. However, as far as I can
understand, many of the things that you describe can relatively easily
be achieved by using your own custom metaclasses. The default
standard-class provides features that were deemed useful for a broad
range of scenarios, but more specific features were left for such custom
metaclasses.

Adding/removing slots is maybe a bit harder than necessary, but
certainly possible, and writing a graphical user interface for
manipulating classes and their hierarchies doesn't happen that often,
does it? So I guess the compromise they made there is ok.

Some design choices in CLOS seem to have been motivated by a wish to
compete with other object-oriented languages, which due to their
restrictions could (and can) be implemented more efficiently. That's
maybe a pity indeed.

jos...@lisp.de

unread,
Jun 28, 2010, 9:01:09 AM6/28/10
to

Fortunately a lot of stuff is possible with the MOP
and it is good to have a library that unifies
the MOP over implementations. Thanks for that.


> Adding/removing slots is maybe a bit harder than necessary, but
> certainly possible, and writing a graphical user interface for
> manipulating classes and their hierarchies doesn't happen that often,
> does it? So I guess the compromise they made there is ok.

I think it is absolute crucial if you want to
design user interfaces. The first modern UI designer
was written in Lisp and later reimplemented at Apple.
This UI designer is at the heart of many of the
nice applications for the Mac/iPhone/iPad.
Basically in any application like this you
put some object on the screen and give it some class.
Often one would just subclass, say, a button, give that
some slots and put a such a button on the screen.
Later one might need another slot, add it to the
class and the buttons on the screen are changed...
I find these are quite common use cases in
designing User Interfaces of all kinds.

I fear that these use cases come up not that often,
because some capabilities needed for that are not
obvious in CLOS (though possible) and thus CLOS/CL
is less used for that. I fear
it is not that these use cases are rare and thus
capabilities are not needed (in a straightforward) way.

Alessio Stalla

unread,
Jun 28, 2010, 9:09:22 AM6/28/10
to
On Jun 28, 1:00 am, "Scott L. Burson" <g...@zeta-soft.com> wrote:
> For those with more MOP experience than I, what's the easiest way to
> programmatically add a slot to an existing class?

IIRC, one of the examples in AMOP was about adding some kind of
"dynamic slots" to CLOS. They were implemented as a map stored in a
"private" slot, so not as efficient as regular slots, but it can be a
start.

hth,
Alessio

Scott L. Burson

unread,
Jun 28, 2010, 3:20:46 PM6/28/10
to
On Jun 28, 12:09 am, Pascal Costanza <p...@p-cos.net> wrote:
> On 28/06/2010 01:00, Scott L. Burson wrote:
>
> > For those with more MOP experience than I, what's the easiest way to
> > programmatically add a slot to an existing class?
>
> The situations were you may want to do this are usually extremely rare.
> So it may be useful to tell us what you want to achieve, so we can maybe
> come up with better solutions.

I just wanted to extend a class whose definition I don't control. I
could just load a patch containing the DEFCLASS form with my slot
added -- I do have access to the original DEFCLASS form -- but then if
it changed, I would have to update my patch. Doing it this way makes
it reasonably upgrade-proof.

Pascal B's code is working fine for me. Maybe something like this
belongs in Closer, or in a CLOS utilities library?

BTW I agree with Rainer -- these situations are not rare at all in my
experience. For years I used a language called Refine in which slot
definitions were not part of the class definition but were separate
top-level syntactic entities. It was therefore trivial, for example,
to declare a class with some of its slots in one source file, and to
add additional slots to it in another source file. (There was a way
to interactively request the entire list of slots, in case one needed
to know, but this need arose less often than one might expect.)

Like a lot of things, this flexibility could be abused, but used
intelligently it was quite handy.

-- Scott

Christophe Rhodes

unread,
Jun 29, 2010, 2:58:07 AM6/29/10
to
"Scott L. Burson" <gy...@zeta-soft.com> writes:

> On Jun 28, 12:09 am, Pascal Costanza <p...@p-cos.net> wrote:
>> On 28/06/2010 01:00, Scott L. Burson wrote:
>>
>> > For those with more MOP experience than I, what's the easiest way to
>> > programmatically add a slot to an existing class?
>>
>> The situations were you may want to do this are usually extremely rare.
>> So it may be useful to tell us what you want to achieve, so we can maybe
>> come up with better solutions.
>
> I just wanted to extend a class whose definition I don't control. I
> could just load a patch containing the DEFCLASS form with my slot
> added -- I do have access to the original DEFCLASS form -- but then if
> it changed, I would have to update my patch. Doing it this way makes
> it reasonably upgrade-proof.

For what it's worth: I'd be tempted to add in a superclass mixin
containing your slot, rather than patch in the slot directly; the effect
is basically the same, but maybe marginally more upgrade-proof?

However, is this not a sign that something somewhere else isn't quite
right? The "normal" way to do this would be to arrange that you use a
subclass of the original class, creating instances of that class and
passing them around, or (if necessary) change-classing the instances you
get given. Not that that's necessarily expedient, and of course you
might be doing something that's a long way from "normal" -- but maybe
the protocol you're using upstream is wrong?

Christophe

Pascal Costanza

unread,
Jun 29, 2010, 5:46:12 AM6/29/10
to

Manipulation of CLOS classes was actually one of the ingredients of
AspectL, my first experiment at providing "crosscutting" functionality
for CLOS. AspectL provides a number of functions (like slot-add,
slot-remove, slot-set, class-add, class-remove and class-set) with which
you can do fine-grained manipulations of CLOS classes.

This functionality is quite problematic, because it is in some cases
hard to decide how the changes should be merged with the existing
information that's already in the class. Say, there are already readers
and writers defined on a given slot, and now you want to add another
reader - does that replace the old readers, or does that just add more
readers? Some of these decisions feel very ad hoc - you basically have
to go through each and every class option and slot option and decide
what good semantics could be. And then you still haven't covered the
cases for user-defined class and slot options from user-defined
metaclasses, so you would have to add another meta layer to be able to
integrate such extensions as well.

This functionality was also quite unstable: Depending on what you did,
it was very easy to crash the whole system. In the end I decided that
it's not worth the hassle of trying to deal with each and every possible
corner case.

I think an easier approach is to use eval here, so to redefine classes
by way of (eval `(defclass ...)), or (funcall (compile nil `(lambda ()
(defclass ...))))). You need to reconstruct the defclass form in order
to do so, by using the MOP facilities to inspect existing classes, but
at least then you have the responsibility of being precise how to merge
existing information with your new one. I know this is not ideal either,
but since there is no ideal solution...

It should be relatively easy for a GUI-based tool to construct defclass
forms from user input, right?

Pascal Costanza

unread,
Jun 29, 2010, 5:55:39 AM6/29/10
to
On 28/06/2010 21:20, Scott L. Burson wrote:
> On Jun 28, 12:09 am, Pascal Costanza<p...@p-cos.net> wrote:
>> On 28/06/2010 01:00, Scott L. Burson wrote:
>>
>>> For those with more MOP experience than I, what's the easiest way to
>>> programmatically add a slot to an existing class?
>>
>> The situations were you may want to do this are usually extremely rare.
>> So it may be useful to tell us what you want to achieve, so we can maybe
>> come up with better solutions.
>
> I just wanted to extend a class whose definition I don't control. I
> could just load a patch containing the DEFCLASS form with my slot
> added -- I do have access to the original DEFCLASS form -- but then if
> it changed, I would have to update my patch. Doing it this way makes
> it reasonably upgrade-proof.

(defclass my-class (third-party-class)
((my-additional-slot ...)))

(defmethod make-instance ((class (eql 'third-party-class)) &rest args)
(apply #'make-instance 'my-class args))

This is not 100% fool-proof, but since your solution is not 100%
fool-proof either, I think I would prefer my solution.

> Pascal B's code is working fine for me. Maybe something like this
> belongs in Closer, or in a CLOS utilities library?

No, because it's really hard to come up with good solutions for the
really tough corner cases. I think it's better to use ad hoc solutions
for the concrete problems you actually have, and the MOP API is good
enough to accommodate this.

> BTW I agree with Rainer -- these situations are not rare at all in my
> experience. For years I used a language called Refine in which slot
> definitions were not part of the class definition but were separate
> top-level syntactic entities. It was therefore trivial, for example,
> to declare a class with some of its slots in one source file, and to
> add additional slots to it in another source file. (There was a way
> to interactively request the entire list of slots, in case one needed
> to know, but this need arose less often than one might expect.)
>
> Like a lot of things, this flexibility could be abused, but used
> intelligently it was quite handy.

Here is another way to achieve what you want:

(defvar *external-store* (make-weak-hash-table :test #'equal))

(defmethod slot-missing
((class standard-class) (object third-party-class)
slot-name operation &optional new-value)
(ecase operation
(slot-value (multiple-value-bind
(value foundp)
(gethash (list object slot-name) *external-store*)
(if foundp value
(slot-unbound class object slot-name))))
(setf (setf (gethash (list object slot-name) *external-store*)
new-value))
(slot-boundp (nth-value 1 (gethash (list object slot-name)
*external-store*))))
(slot-makunbound (remhash (list object slot-name) *external-store*)
object)))

Again, not 100% fool-proof, but ANSI-compliant, without any need for the
CLOS MOP. [untested]

Pascal Costanza

unread,
Jun 29, 2010, 5:56:42 AM6/29/10
to

Originally, such dynamic slots were actually intended for inclusion in
CLOS, as an :allocation :dynamic option. It's a pity that this was left
out. (This would have been much more useful than, say, :allocation :class.)

Kenneth Tilton

unread,
Jun 29, 2010, 6:33:29 AM6/29/10
to
Christophe Rhodes wrote:
> "Scott L. Burson" <gy...@zeta-soft.com> writes:
>
>> On Jun 28, 12:09 am, Pascal Costanza <p...@p-cos.net> wrote:
>>> On 28/06/2010 01:00, Scott L. Burson wrote:
>>>
>>>> For those with more MOP experience than I, what's the easiest way to
>>>> programmatically add a slot to an existing class?
>>> The situations were you may want to do this are usually extremely rare.
>>> So it may be useful to tell us what you want to achieve, so we can maybe
>>> come up with better solutions.
>> I just wanted to extend a class whose definition I don't control. I
>> could just load a patch containing the DEFCLASS form with my slot
>> added -- I do have access to the original DEFCLASS form -- but then if
>> it changed, I would have to update my patch. Doing it this way makes
>> it reasonably upgrade-proof.
>
> For what it's worth: I'd be tempted to add in a superclass mixin
> containing your slot, rather than patch in the slot directly; the effect
> is basically the same, but maybe marginally more upgrade-proof?
>
> However, is this not a sign that something somewhere else isn't quite
> right?

Yes!

> The "normal" way to do this would be to arrange that you use a
> subclass of the original class, creating instances of that class and
> passing them around, or (if necessary) change-classing the instances you
> get given. Not that that's necessarily expedient, and of course you
> might be doing something that's a long way from "normal" -- but maybe
> the protocol you're using upstream is wrong?
>

No! The problem is CLOS, aka the object model. It says we can only store
predined information about an instance and must store that information
for all instances of that class. Not The Lisp Way. The prototype model
is one way out of that trap, but RDF is emerging standard for such things.

kt

--
http://www.stuckonalgebra.com
"The best Algebra tutorial program I have seen... in a class by itself."
Macworld

Robert Swindells

unread,
Jun 29, 2010, 6:49:38 AM6/29/10
to
On Tue, 29 Jun 2010 11:46:12 +0200, Pascal Costanza wrote:

> It should be relatively easy for a GUI-based tool to construct defclass
> forms from user input, right?

I have a copy of a paper that describes the LeLisp version of the interface
builder and saw Jean-Marie Hullot give a presentation and demo of
ExperInterfaceBuilder.

My reading of the paper is that most of the Editors were operating on
instances of pre-defined classes, not defining new classes, I think it
would require a reading of the documentation on the object system used
(Alcyone) to be sure though.

Robert Swindells

Pascal Costanza

unread,
Jun 29, 2010, 7:28:51 AM6/29/10
to

Do you have a reference?

jos...@lisp.de

unread,
Jun 29, 2010, 7:33:42 AM6/29/10
to

In the current Interface Builder one can set the class for an object
and also create 'runtime' properties. But that is
also for a more static setting.

If one uses a Lisp-based interface builder, we can
edit the running interface objects. Like in the interface
Builder for KEE, where you could edit everything
via dialogs and menus. The created objects/classes
(the so-called knowledge base) are
dumped in some external format
and can be reloaded - source code of those is not edited
as text (though UIs can be programmed where necessary).

See here for some KEE in 'action' on my MacIvory 3:

http://www.cl-http.org:8002/mov/lispm-kee.mov

In the video I gave an example how to:

* create objects and classes with a text-based dialog
* change the inheritance via menus
* add graphical displays to slots
* add values to slots

adding a slot would be done via the context-menu
'Create slot' on an object ('UNIT').

In Coral Lisp, one had also a prototype object system,
and adding a slot to an object is just telling
the object to HAVE a slot. There would put
some generic window object on the screen and
add objects/slots/methods to it one by one. This
would also be possible with a CLOS based UI toolkit,
but from a UI designer point of view, one would
need deal with classes a bit, which was not necessary
in Coral Lisp, where I could add slots to objects
and/or inherit from other objects. This leads to a slightly
more fluid incremental workflow.


jos...@lisp.de

unread,
Jun 29, 2010, 7:34:58 AM6/29/10
to
On 29 Jun., 13:28, Pascal Costanza <p...@p-cos.net> wrote:
> On 29/06/2010 12:49, Robert Swindells wrote:
>
> > On Tue, 29 Jun 2010 11:46:12 +0200, Pascal Costanza wrote:
>
> >> It should be relatively easy for a GUI-based tool to construct defclass
> >> forms from user input, right?
>
> > I have a copy of a paper that describes the LeLisp version of the interface
> > builder and saw Jean-Marie Hullot give a presentation and demo of
> > ExperInterfaceBuilder.
>
> > My reading of the paper is that most of the Editors were operating on
> > instances of pre-defined classes, not defining new classes, I think it
> > would require a reading of the documentation on the object system used
> > (Alcyone) to be sure though.
>
> Do you have a reference?

There is a bit of Alcyone here, but not in depth:

http://hal.archives-ouvertes.fr/docs/00/07/00/98/PDF/RT-0060.pdf

Robert Swindells

unread,
Jun 29, 2010, 8:00:11 AM6/29/10
to
On Tue, 29 Jun 2010 13:28:51 +0200, Pascal Costanza wrote:

> On 29/06/2010 12:49, Robert Swindells wrote:
>> On Tue, 29 Jun 2010 11:46:12 +0200, Pascal Costanza wrote:
>>
>>> It should be relatively easy for a GUI-based tool to construct
>>> defclass forms from user input, right?
>>
>> I have a copy of a paper that describes the LeLisp version of the
>> interface builder and saw Jean-Marie Hullot give a presentation and
>> demo of ExperInterfaceBuilder.
>>
>> My reading of the paper is that most of the Editors were operating on
>> instances of pre-defined classes, not defining new classes, I think it
>> would require a reading of the documentation on the object system used
>> (Alcyone) to be sure though.
>
> Do you have a reference?

Not really,

"SOS Interface, Un générateur d'Interfaces Homme - Machine"

from

"Journées Langages Orientés Objet" no date. I got it as a photocopy.

Robert Swindells

Robert Swindells

unread,
Jun 29, 2010, 8:01:40 AM6/29/10
to
On Tue, 29 Jun 2010 04:34:58 -0700, jos...@corporate-world.lisp.de wrote:

> On 29 Jun., 13:28, Pascal Costanza <p...@p-cos.net> wrote:
>> On 29/06/2010 12:49, Robert Swindells wrote:
>>
>> > On Tue, 29 Jun 2010 11:46:12 +0200, Pascal Costanza wrote:
>>
>> >> It should be relatively easy for a GUI-based tool to construct
>> >> defclass forms from user input, right?
>>
>> > I have a copy of a paper that describes the LeLisp version of the
>> > interface builder and saw Jean-Marie Hullot give a presentation and
>> > demo of ExperInterfaceBuilder.
>>
>> > My reading of the paper is that most of the Editors were operating on
>> > instances of pre-defined classes, not defining new classes, I think
>> > it would require a reading of the documentation on the object system
>> > used (Alcyone) to be sure though.
>>
>> Do you have a reference?
>
> There is a bit of Alcyone here, but not in depth:
>
> http://hal.archives-ouvertes.fr/docs/00/07/00/98/PDF/RT-0060.pdf

That is the technical report referenced in the paper that I have,
thanks.

Robert Swindells

Scott L. Burson

unread,
Jun 29, 2010, 5:51:18 PM6/29/10
to
On Jun 29, 2:55 am, Pascal Costanza <p...@p-cos.net> wrote:
>
> (defclass my-class (third-party-class)
>    ((my-additional-slot ...)))
>
> (defmethod make-instance ((class (eql 'third-party-class)) &rest args)
>    (apply #'make-instance 'my-class args))
>
> This is not 100% fool-proof, but since your solution is not 100%
> fool-proof either, I think I would prefer my solution.

A very interesting suggestion, and I see why you like it. I note
however that it doesn't compose: you couldn't do this in two places.

> > Pascal B's code is working fine for me.  Maybe something like this
> > belongs in Closer, or in a CLOS utilities library?
>
> No, because it's really hard to come up with good solutions for the
> really tough corner cases. I think it's better to use ad hoc solutions
> for the concrete problems you actually have, and the MOP API is good
> enough to accommodate this.

Fair enough.

> > BTW I agree with Rainer -- these situations are not rare at all in my
> > experience.  For years I used a language called Refine in which slot
> > definitions were not part of the class definition but were separate
> > top-level syntactic entities.  It was therefore trivial, for example,
> > to declare a class with some of its slots in one source file, and to
> > add additional slots to it in another source file.  (There was a way
> > to interactively request the entire list of slots, in case one needed
> > to know, but this need arose less often than one might expect.)
>
> > Like a lot of things, this flexibility could be abused, but used
> > intelligently it was quite handy.
>
> Here is another way to achieve what you want:
>
> (defvar *external-store* (make-weak-hash-table :test #'equal))

> [...]


>
> Again, not 100% fool-proof, but ANSI-compliant

Umm... except for the MAKE-WEAK-HASH-TABLE part :)

But yes, in most implementations, this is also a reasonable
suggestion.

-- Scott

Scott L. Burson

unread,
Jun 29, 2010, 10:05:05 PM6/29/10
to
On Jun 28, 11:58 pm, Christophe Rhodes <cs...@cantab.net> wrote:

> "Scott L. Burson" <g...@zeta-soft.com> writes:
>
> > On Jun 28, 12:09 am, Pascal Costanza <p...@p-cos.net> wrote:
> >> On 28/06/2010 01:00, Scott L. Burson wrote:
>
> >> > For those with more MOP experience than I, what's the easiest way to
> >> > programmatically add a slot to an existing class?
>
> >> The situations were you may want to do this are usually extremely rare.
> >> So it may be useful to tell us what you want to achieve, so we can maybe
> >> come up with better solutions.
>
> > I just wanted to extend a class whose definition I don't control.  I
> > could just load a patch containing the DEFCLASS form with my slot
> > added -- I do have access to the original DEFCLASS form -- but then if
> > it changed, I would have to update my patch.  Doing it this way makes
> > it reasonably upgrade-proof.
>
> For what it's worth: I'd be tempted to add in a superclass mixin
> containing your slot, rather than patch in the slot directly; the effect
> is basically the same, but maybe marginally more upgrade-proof?

I don't see offhand how it would be any more upgrade-proof.

> However, is this not a sign that something somewhere else isn't quite
> right?  The "normal" way to do this would be to arrange that you use a
> subclass of the original class, creating instances of that class and
> passing them around

In this particular case, that wouldn't be hard. In general, though,
it can be more difficult.

I think a program organization that allows slot definitions to appear
in various locations in the source code could be described as aspect-
oriented rather than object-oriented. (I faintly recall that AspectJ
(which I have never used but heard a talk about once) has a way to add
a slot to a class.) I think it's a valid and sometimes useful way of
organizing code, despite the fact that it seems strange and wrong to
people used to object-oriented organization.

-- Scott

Christophe Rhodes

unread,
Jun 30, 2010, 2:24:16 AM6/30/10
to
"Scott L. Burson" <gy...@zeta-soft.com> writes:

> On Jun 28, 11:58 pm, Christophe Rhodes <cs...@cantab.net> wrote:
>> For what it's worth: I'd be tempted to add in a superclass mixin
>> containing your slot, rather than patch in the slot directly; the effect
>> is basically the same, but maybe marginally more upgrade-proof?
>
> I don't see offhand how it would be any more upgrade-proof.

Ah, I missed out a detail: it's fairly easy to also write a method on
the MOP function ENSURE-CLASS-USING-CLASS to make sure that all these
extra added superclasses are preserved if and when the original DEFCLASS
(without any mention of superclasses) is re-evaluated, say to fix some
unrelated problem. (This is a technique used in gsharp, for example).
You could probably do something like this with slots, too, but it's
somewhat trickier to construct the slot definitions, and a little harder
to redefine the added slots (whereas redefining the added mixin classes
also "just works").

Christophe

Pascal Costanza

unread,
Jul 2, 2010, 6:47:44 AM7/2/10
to

Ah, if you want to do this in a AOP-style, you can actually use ContextL:

(define-layered-class person ()
((name :initarg :name :reader person-name)))

(deflayer additional-slots)

(define-layered-class person :in-layer additional-slots ()
((address :initarg :address :reader person-address)))

etc.

You can add as many layers as you want (you would usually use more
declarative names). The typical use case is to use dynamically scoped
layer activation, but you can also activate layers globally via
'ensure-active-layer. (Partial) class definitions will be composed into
the running system, and all existing instances of adapted classes will
be updated.

This is less dynamic than what Rainer shows in his video, for example,
but a lot more dynamic than plain CLOS.

Scott L. Burson

unread,
Jul 3, 2010, 2:34:54 PM7/3/10
to

Cool! I'm glad to know this, though it doesn't help with this
particular case since I don't control the original DEFCLASS form. But
I will take a look at ContextL for other uses.

-- Scott

0 new messages