0

Is there a way to dynamically ask for bindings in another package, and by dynamically i mean by not knowing the exact name of a binding in some package. A concrete case would be:

As in package B, i know there exists a package A which has a certain class and i extract all direct slots of that class by (in LispWorks):

(setq direct-slots (mapcar #'slot-definition-name
                           (class-direct-slots (class-of class-in-package-A))))

Now i want to bind those slots to some values using MAPCAR:

(mapcar #'(lambda (slot) (list slot
                               (funcall slot class-in-package-A)))
             direct-slots)

This doesn't work since i am in package B and need package precision for the call to (funcall slot class-in-package-A), packageA::slot is obviously wrong. Is there a function for this which searchs for a certain symbol in a package?

Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
  • 2
    CLASS-OF ? You are asking for the meta-class then. – Rainer Joswig Jul 04 '19 at 12:51
  • 2
    A slot name is generally not a function name, thus it makes no sense to call it. Do you actually want to call a slot-name on a class object? Is that what you want? A class object is a metaclass. – Rainer Joswig Jul 04 '19 at 12:53
  • 2
    Maybe you should post code, which can be reproduced with actual error messages. It's not clear what you might want to do has to do with packages. – Rainer Joswig Jul 04 '19 at 12:56

1 Answers1

2

If you have a slot-name and want to get the value of the named slot in some object, use slot-value:

(mapcar (lambda (slot-name)
          (slot-value some-object slot-name))
        slot-names)

Slot names are symbols, and they will not magically lose their package if you happen to “be” in a different package. I think your confusion is that you are thinking about accessors, but those are a different thing (they use something like slot-value internally).

CL-USER> (defpackage #:foo
           (:use #:cl))
#<PACKAGE "FOO">
CL-USER> (defpackage #:bar
           (:use #:cl #:sb-mop))  ; in SBCL
#<PACKAGE "BAR">
CL-USER> (in-package #:foo)
#<PACKAGE "FOO">
FOO> (defclass afoo ()
       ((a :initarg :a)
        (b :initarg :b)))
#<STANDARD-CLASS FOO::AFOO>
FOO> (in-package #:bar)
#<PACKAGE "BAR">
BAR> (mapcar #'slot-definition-name
             (class-direct-slots (find-class 'foo::afoo)))
(FOO::A FOO::B)
BAR> (let ((slot-names (mapcar #'slot-definition-name
                               (class-direct-slots (find-class 'foo::afoo))))
           (obj (make-instance 'foo::afoo
                               :a 1
                               :b 2)))
       (mapcar (lambda (slot-name)
                 (slot-value obj slot-name))
               slot-names))
(1 2)

In general, you should be using accessors in “user” code, and you should know which accessors exist for a given object. It also shouldn't matter for user code whether something is a direct slot.

Svante
  • 50,694
  • 11
  • 78
  • 122