4

The following code does what I want:

 1 (defclass some-class ()
 2   ((some-slot
 3       :initarg :somearg
 4       :initform (error ":somearg not specified"))))
 5 (defparameter *alpha* (make-instance 'some-class :somearg 3))
 6 (defparameter *beta*  (make-instance 'some-class :somearg 5))
 7 (defparameter *gamma* (make-instance 'some-class :somearg 3))
 8 (princ (slot-value *beta* 'some-slot)) (terpri)
 9 (defparameter *delta* (list *alpha* *beta* *gamma*))
10 (princ *delta*) (terpri)
11 (princ (remove-duplicates *delta*
12          :test #'equal
13          :key (lambda (x) (slot-value x 'some-slot))))
14 (terpri)
5
(#<SOME-CLASS #x21C1D71E> #<SOME-CLASS #x21C1DAFE> #<SOME-CLASS #x21C1DC3E>)
(#<SOME-CLASS #x21C1DAFE> #<SOME-CLASS #x21C1DC3E>)

But is there a way to do this without having to write the function on line 13? Is there a shorthand way to specify as the key a slot value in the class instance?

The following blows up with a syntax error, of course, but it gives the general idea of what I'm seeking.

 1 (princ (remove-duplicates *delta*
 2          :test #'equal
 3          :key '(slot-value 'some-slot)))
 4 (terpri)
*** - FUNCALL: (SLOT-VALUE 'SOME-SLOT) is not a function name; try using a
      symbol instead
Inaimathi
  • 13,853
  • 9
  • 49
  • 93
Bill Evans at Mariposa
  • 3,590
  • 1
  • 18
  • 22

2 Answers2

3

You could try a :reader or :accessor.

Doing

(defclass some-class ()
  ((some-slot
    :initarg :somearg :reader some-slot
    :initform (error ":somearg not specified"))))

should let you re-write lines 11 through 13 as

(princ (remove-duplicates *delta* :test #'equal :key #'some-slot))

That is, (some-slot x) is equivalent to (slot-value x 'some-slot) if the slot in question has a reader/accessor.


After-Sleep Edit:

You also don't need to bother setting :initform to error; a slot will do that by default if you don't specify a default value and someone tries to read it. If you don't want the error, you do something like :initform nil. Check out this excellent CLOS tutorial as well as chapters 16 and 17 of Practical Common Lisp for more information about objects in Common Lisp.

Also, in the future if you have working code that you'd like style advice on, do check out codereview.stackexchange. There's a small, but active population of Lisp reviewers.

Community
  • 1
  • 1
Inaimathi
  • 13,853
  • 9
  • 49
  • 93
  • 1
    Inaimathi, the reason I set :initform to error is to trigger an error not when the slot is accessed, but earlier, when the object is created. Does that do this for me? – Bill Evans at Mariposa Jan 31 '12 at 05:25
  • 1
    @Bill - Ah, I see. No, the default behavior is to error when an unset slot is accessed. You got it then. – Inaimathi Jan 31 '12 at 13:33
2

You could define a reader function for the slot in the defclass and provide that as key function to remove-duplicates. For example, add this line to the slot definition:

:reader some-slot

and then use this in the call of remove-duplicates:

:key #'some-slot
Rörd
  • 6,556
  • 21
  • 27