Search code examples
common-lispclos

How to point to a defgeneric instance in common-lisp CLOS


lisp beginner here.

I get how to point to a specific method instance using function find-method and I see from using slime inspect on the returned method instance that it has a slot %GENERIC-FUNCTION, but I cannot use it.

(why does (slot-value (find-method ...) '%GENERIC-FUNCTION) tells me that the slot is missing from the object.

So, how should I do to point to a defgeneric from a defmethod object ? I'm using a sbcl, but is there a standardized common-lisp way to do it for compatibility ?


Solution

  • %GENERIC-FUNCTION probably refers to a symbol in your current package, and not the symbol in the internal package that identifies the slot. They have the same name, but belong to different packages.

    What you are doing is related to the Meta-Object Protocol (MOP) of CLOS, please refer to metamodular.com/CLOS-MOP for more information (also, read AMOP).

    Let's first load closer-mop:

    USER> (ql:quickload :closer-mop)
    To load "closer-mop":
      Load 1 ASDF system:
        closer-mop
    ; Loading "closer-mop"
    
    (:CLOSER-MOP)
    

    The Closer-MOP system is:

    [...] a compatibility layer that rectifies many of the absent or incorrect CLOS MOP features across a broad range of Common Lisp implementations.

    USER> (find-method #'print-object () (mapcar #'find-class '(vector t)))
    #<STANDARD-METHOD COMMON-LISP:PRINT-OBJECT (VECTOR T) {10005605C3}>
    

    (Thanks to RainerJoswig for pointing out that the list of specializers should contain class objects and not symbols)

    USER> (closer-mop:class-direct-slots (class-of *))
    (#<SB-MOP:STANDARD-DIRECT-SLOT-DEFINITION SB-PCL::%GENERIC-FUNCTION>
     #<SB-MOP:STANDARD-DIRECT-SLOT-DEFINITION SB-PCL::QUALIFIERS>
     #<SB-MOP:STANDARD-DIRECT-SLOT-DEFINITION SB-PCL::SPECIALIZERS>
     #<SB-MOP:STANDARD-DIRECT-SLOT-DEFINITION SB-PCL::LAMBDA-LIST>
     #<SB-MOP:STANDARD-DIRECT-SLOT-DEFINITION SB-PCL::%FUNCTION>
     #<SB-MOP:STANDARD-DIRECT-SLOT-DEFINITION SB-PCL::%DOCUMENTATION>
     #<SB-MOP:STANDARD-DIRECT-SLOT-DEFINITION SB-PCL::SIMPLE-NEXT-METHOD-CALL>)
    

    So indeed, you need to use the SB-PCL::%GENERIC-FUNCTION symbol:

    USER> (slot-value ** 'SB-PCL::%GENERIC-FUNCTION)
    #<STANDARD-GENERIC-FUNCTION COMMON-LISP:PRINT-OBJECT (277)>
    

    (recall that * and ** are variables that represent the last and second to last values evaluated in a REPL)

    Remark

    The SB-PCL::%GENERIC-FUNCTION symbol for this slot is not exported (we need two colons to refer to it), and it starts with a % character, which is a convention for internal (sometimes dangerous) symbols. You should not use it directly; also calling slot-value directly is not recommanded, usually you only need accessor functions.

    method-generic-function

    Instead, you should use the symbols exported from closer-mop for better compatibility:

    (closer-mop:method-generic-function 
      (find-method #'print-object () (mapcar #'find-class '(vector t))))