I'm having a problem acessing slots out of slot definitions. I can inspect class objects, see their slots definitions and even get some standard info about the slots definitions. However I can't access user-defined information about the slot definition.
I've already googled this for quite a while and ended up reading CLOS & MOP specifications, a bit of the Lisp Cookbook, about some MOP concepts, and some related questions on StackOverflow that didn't help much. I even readed a piece of SBCL's implementations, but to no avail.
From the pieces that I was able to put together, I can access many slots of a SLOT DEFINITION
via some functions, e.g. access the NAME
slot of the SLOT DEFINITION
using CLOSER-MOP:SLOT-DEFINITION-NAME
(which is certainly helpful), but I can't do so for slots that don't have one of these functions. For example, I can't access the REFERENCES
slot which is provided by the MITO
package when defining slots in a DEFCLASS
.
Here's a minimal working example:
(load "~/quicklisp/setup.lisp")
;;;; I'll use MITO because its classes have a funny REFERENCES slot
(quicklisp:quickload :mito)
;;;; I find CLOSER-MOP functions easier to use than
;;;; implementation-specific functions
(quicklisp:quickload :closer-mop)
;;;; Creates a few dummy classes
(defclass example ()
((one-slot :col-type (:varchar 50)
:accessor one-slot-accessor))
(:metaclass mito:dao-table-class)
(:documentation "An example class."))
(defclass another-example ()
((normal-slot :col-type (:varchar 50)
:accessor normal-slot-accessor)
(example-reference :references (example id)
:reader example-reference-accessor))
(:metaclass mito:dao-table-class)
(:documentation "Another example class which references `EXAMPLE' class."))
;;;; Now try to see what's inside those classes
(let* ((class (find-class 'another-example))
(slots (closer-mop:class-direct-slots class))
(slot-i-am-interested (second slots)))
(inspect slot-i-am-interested) ; Oh, apparently we have a REFERENCES slot
;; Why can't SLOT-VALUE access the REFERENCES slot?
(slot-value slot-i-am-interested 'references))
Note that I am NOT accessing any database or anything similar, although I'm using MITO
(I don't think I would get this problem if I didn't use any custom slot, like the REFERENCES
one that MITO
provides). It's just plain CLOS/MOP manipulation.
The usual output is something like (the exact output depends on your Common Lisp implementation):
user@linuxstudio:~/dev/lisp/slot-question-so$ sbcl --script example.lisp
To load "mito":
Load 1 ASDF system:
mito
; Loading "mito"
....
To load "closer-mop":
Load 1 ASDF system:
closer-mop
; Loading "closer-mop"
The object is a STANDARD-OBJECT of type MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS.
0. SOURCE: #S(SB-C:DEFINITION-SOURCE-LOCATION
:NAMESTRING "/home/user/dev/lisp/slot-question-so/example.lisp"
:INDICES 163840)
1. NAME: EXAMPLE-REFERENCE
2. INITFORM: NIL
3. INITFUNCTION: NIL
4. INITARGS: (:EXAMPLE-REFERENCE)
5. %TYPE: T
6. %DOCUMENTATION: NIL
7. %CLASS: #<MITO.DAO.TABLE:DAO-TABLE-CLASS COMMON-LISP-USER::ANOTHER-EXAMPLE>
8. READERS: (EXAMPLE-REFERENCE-ACCESSOR)
9. WRITERS: NIL
10. ALLOCATION: :INSTANCE
11. ALLOCATION-CLASS: NIL
12. COL-TYPE: NIL
13. REFERENCES: (EXAMPLE ID)
14. PRIMARY-KEY: NIL
15. GHOST: NIL
16. INFLATE: "unbound"
17. DEFLATE: "unbound"
> q
So, apparently, we do have a REFERENCES
slot. However, after INSPECT
, when we try to SLOT-VALUE
the slot, we get an SLOT-MISSING
error (showing only the first lines of the backtrace):
Unhandled SIMPLE-ERROR in thread #<SB-THREAD:THREAD "main thread" RUNNING
{10005E85B3}>:
When attempting to read the slot's value (slot-value), the slot REFERENCES is
missing from the object
#<MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS COMMON-LISP-USER::EXAMPLE-REFERENCE>.
Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING {10005E85B3}>
0: (SB-DEBUG::DEBUGGER-DISABLED-HOOK #<SIMPLE-ERROR "~@<When attempting to ~A, the slot ~S is missing from the ~
object ~S.~@:>" {1004B1B803}> #<unused argument> :QUIT T)
1: (SB-DEBUG::RUN-HOOK *INVOKE-DEBUGGER-HOOK* #<SIMPLE-ERROR "~@<When attempting to ~A, the slot ~S is missing from the ~
object ~S.~@:>" {1004B1B803}>)
2: (INVOKE-DEBUGGER #<SIMPLE-ERROR "~@<When attempting to ~A, the slot ~S is missing from the ~
object ~S.~@:>" {1004B1B803}>)
3: (ERROR "~@<When attempting to ~A, the slot ~S is missing from the ~
object ~S.~@:>" "read the slot's value (slot-value)" REFERENCES #<MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS COMMON-LISP-USER::EXAMPLE-REFERENCE>)
4: ((:METHOD SLOT-MISSING (T T T T)) #<unused argument> #<MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS COMMON-LISP-USER::EXAMPLE-REFERENCE> REFERENCES SLOT-VALUE NIL) [fast-method]
5: ((LAMBDA (SB-PCL::OBJECT) :IN SB-PCL::SLOT-MISSING-INFO) #<MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS COMMON-LISP-USER::EXAMPLE-REFERENCE>)
6: ((LAMBDA NIL :IN "/home/user/dev/lisp/slot-question-so/example.lisp"))
So how can I access the "slot" REFERENCES
? Is that really a slot? If no, how can I access it? Why a simple SLOT-VALUE
doesn't work in this case?
Can you point me to some documentation about this topic to provide more information in case I want to understand more about this?
I'm using SBCL 1.4.5.debian
as my lisp implementation, if that may be important.
(slot-value slot-i-am-interested 'references)
, you're looking for a slot namedCL-USER::REFERENCES
, but the slot actually seems to be namedMITO.CLASS.COLUMN::REFERENCES
. – jkiiski'REFERENCES
with'MITO.CLASS.COLUMN::REFERENCES
solved my problem. It's been a while since I read about packages in lisp, so I can't remember many of details about handling symbols and packages. If you provide your comment as an answer I would be glad to accept it. How did you know it wasMITO.CLASS.COLUMN::
and not e.g.MITO.DAO.COLUMN::
orMITO.DAO.TABLE::
? – Gabriel Francischiniinspect
output and neither mentionsMITO.CLASS.COLUMN
. It looks like a magical value, but it works. How you discovered/guessed it? – Gabriel Francischini