Retrieving slot names from class

Discussion of Common Lisp
janders468
Posts: 16
Joined: Fri Oct 17, 2008 12:27 pm

Retrieving slot names from class

Post by janders468 » Thu Jan 22, 2009 8:13 pm

Is there a Common Lisp method that will allow me to get back a list of the names of all the slots for a given class, i'm hoping if there is one it is part of the standard, but I'm using SBCL for this if they happen to have this as an extension. Thanks in advance.

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Retrieving slot names from class

Post by ramarren » Thu Jan 22, 2009 10:59 pm

There is MetaObject Protocol, which is not a standard, but a common extension. Unfortunately, most implementations have subtle (or not so subtle) differences in their implementations of it, but fortunately there is http://common-lisp.net/project/closer/closer-mop.html, which is a compatibility library. The full description is in a book called "Art of the MetaObject Protocol", part of which is available in http://www.lisp.org/mop/index.html.

I have never used it, but you probably want either CLASS-SLOTS or COMPUTE-SLOTS. Why do you need these slots anyway?

janders468
Posts: 16
Joined: Fri Oct 17, 2008 12:27 pm

Re: Retrieving slot names from class

Post by janders468 » Fri Jan 23, 2009 9:11 am

I've found that it comes up a lot in my own classes that there is something I want to be able to do for every slot in a hierarchy of classes. For example if I wanted to print all the slots and their values for any class in a hierarchy

(defclass foo-super ()
((slot1)
(slot2)))

(defclass foo-sub (foo-super)
((slot3)
(slot4)))

(defmethod print-object ((var foo-super) stream)
;assuming slot-list returns a list of all the slots
(loop for slot in (slot-list var)
do (format stream ("Slot: ~a Value: ~A" slot (slot-value var slot)))))

Without access to the slot names I have to define a method for each one of these using with-slots or with-accessors or something along those lines.
If you have any ideas or if it appears I'm thinking about this in a backwards way let me know.

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Retrieving slot names from class

Post by ramarren » Fri Jan 23, 2009 9:56 am

From what I have seen there are two solutions to this kind of problems. Well, maybe three, since the first thing you should consider is thinking not in terms of objects, but generic functions, or protocols in general. Doing the same operation on every slot in an object should be pretty rare, because it means that either the operation is highly generic, and there are only so many of those, like serialization, and for most of those there are libraries already, or the data in an object is highly homogeneous, in which case a different data structure might be better.

Anyway, as I said, there are two approaches here. One is, as I pointed in the post above, to use MOP. The other is to write your own defclass-like macro, which will save the slots list somewhere. Using MOP is more elegant, but then you probably will want to read AMOP, and in some implementations MOP is spotty.

janders468
Posts: 16
Joined: Fri Oct 17, 2008 12:27 pm

Re: Retrieving slot names from class

Post by janders468 » Fri Jan 23, 2009 10:15 am

Could you expound a little further on option 1 (generic functions and protocols). I certainly understand both the options with mop and a defclass like macro, but (and I apologize in advance if I'm over simplifying things) aren't I trying to do this with generic functions? How, given what you said would you approach the above example (trivial as it is). In a more generic function or protocol way? I'm just trying to get a better understanding of what you are saying.

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Retrieving slot names from class

Post by ramarren » Fri Jan 23, 2009 10:30 am

I would approach the example in the "don't do that" way ;) That is, printing all slots in an object instance is not very useful for anything other than debugging, and debugging is better done when thinking more about verbs than nouns. And if state of some particular object is important, then it is better to use inspector, especially when backed with Slime, than manually messing with internals.

janders468
Posts: 16
Joined: Fri Oct 17, 2008 12:27 pm

Re: Retrieving slot names from class

Post by janders468 » Fri Jan 23, 2009 10:37 am

Yeah, I wouldn't do that, it was just an example of something you could do. I'm not actually trying to figure out how to print all slots from a hierarchy of classes. I was just hoping the example of something that could be done if you could iterate all the slots would help illuminate my thinking on how to view problems of this nature in the future.

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Retrieving slot names from class

Post by ramarren » Fri Jan 23, 2009 10:49 am

My point was that iterating over all slots in a class is not actually that useful for any non-contrived objective, except serialization/persistence, for which there are libraries already. Which means that this is not a problem one should worry about. Anything that would require it can be either done in a more simple way, or has to be done utilizing much more of the MOP. But I don't claim any authority on the subject.

janders468
Posts: 16
Joined: Fri Oct 17, 2008 12:27 pm

Re: Retrieving slot names from class

Post by janders468 » Fri Jan 23, 2009 4:37 pm

Okay, if anybody is interested I have solved this for my purposes. The solution is certainly in the MOP, thanks Ramarran for pointing me in that direction. I'll explain briefly what I found, but please note I've only studied the MOP documentation noted above for an hour or so, so my terminology is sure to be off, and if my conceptual grasp is lacking I would love to be set straight. As has been established a standard object is created based on the MOP, this means that every object (unless of course you're using a different protocol) is created according to the metaobject class standard-class. There are numerous introspective methods specialized on the instance of the metaclass associated with a the object created, in my example above class foo-super and foo-sub. The key to getting at this data is manipulating the instance of the metaclass of your class (foo-super or foo-sub). This bridge is gapped via the function find-class (maybe in other ways?), i.e. (find-class 'foo) will return the metaclass instance associated with class foo. It is fairly trivial from that point to extract whatever information about class foo you want so following my above example (initforms added so we don't run into any slot unbound errors obviously this is all trivial and contrived):

(defclass foo-super ()
((slot1 :initform 1)
(slot2 :initform 2)))

(defclass foo-sub(foo-super)
((slot3 :initform 3)
(slot4 :initform 4)))

(defmethod print-object ((var foo-super) stream)
(loop for slot in (sb-mop::compute-slots (find-class (type-of var)))
do (format stream "Slot Name: ~A Slot Value: ~A~&" (sb-mop::slot-definition-name slot) (slot-value var (sb-mop::slot-definition-name slot)))))

REPL>(make-instance 'foo-sub)
Slot Name: SLOT1 Slot Value: 1
Slot Name: SLOT2 Slot Value: 2
Slot Name: SLOT3 Slot Value: 3
Slot Name: SLOT4 Slot Value: 4


I'm using SBCL so the MOP methods are found in package sb-mop, this is obviously implementation dependent. I also tried this in allegro cl (in package mop). It behaved differently in that on SBCL the above will print all 4 slots, but in allegro it only prints the derived slots. I'm not sure why that is, or what would be considered more conforming, but the former (SBCL way) is what I was looking for and works for my purposes. The other thing to note is that in SBCL this causes an error if the class has not been finalized, which I gather happens at object creation, or when manually invoked, again via the metaobject class instance. I would be happy to expound if anyone is interested. Hopefully this will help someone else too.

matthias.margush

Re: Retrieving slot names from class

Post by matthias.margush » Sun Feb 08, 2009 9:52 pm

If this is for debugging there is (describe):

Code: Select all

CL-USER> (describe (make-instance 'foo-sub))
#<FOO-SUB #x4E36864E>
Class: #<STANDARD-CLASS FOO-SUB>
Wrapper: #<CCL::CLASS-WRAPPER FOO-SUB #x4E36925E>
Instance slots
SLOT1: 1
SLOT2: 2
SLOT3: 3
SLOT4: 4
; No value

Post Reply