(defclass x ()
((integer-value :initarg :integer-value :initform 0)))
(let ((x (make-instance 'x :integer-value "1")))
(values (slot-value x 'integer-value)
(progn
(setf (slot-value x 'integer-value) "2")
(slot-value x 'integer-value))))
;;⇒ 1
;; 2
こんなふうに文字列をわたしても整数変換して欲しい、みたいなことありますよね。
でも次のようにしても (setf slot-value)
はメソッドではないのでエラーなります。
(ignore-errors (defmethod (setf slot-value) ((value string) (x x) (slot (eql 'integer-value)))
(setf (slot-value x slot) (parse-integer value))))
;;⇒ NIL
;; #<SB-INT:SIMPLE-PROGRAM-ERROR "~@<~/sb-ext:print-symbol-with-prefix/ ~
;; already names an ordinary function or a ~
;; macro.~@:>" {100B5BC9A3}>
しかたなので (setf sb-mop:slot-value-using-class)
を経由しました。
(defvar *slot-value-next-method*)
(defmethod (setf %slot-value) (value object slot-name)
(funcall *slot-value-next-method* value))
(defmethod (setf sb-mop:slot-value-using-class) :around (value class (object x) slotd)
(let ((*slot-value-next-method* (lambda (value) (call-next-method value class object slotd))))
(setf (%slot-value object (sb-mop:slot-definition-name slotd)) value)))
(sb-mop:finalize-inheritance (find-class 'x))
(defmethod (setf %slot-value) ((value string) (x x) (slot (eql 'integer-value)))
(setf (%slot-value x slot) (parse-integer value)))
(let ((x (make-instance 'x :integer-value "1")))
(values (slot-value x 'integer-value)
(progn
(setf (slot-value x 'integer-value) "2")
(slot-value x 'integer-value))))
;;⇒ 1
2