eieio:该不该用accessor?


#1

从闭包的角度来讲,外部环境直接用accessor而不是reader和writer是不是不好?毕竟用accessor的话,外部对这个accessor对应的slot做什么就不在原对象的控制之下了。还是说我想多了?

(defclass myclass ()
  ((natual-numbers
    :initarg :natrual-nambers
    :accessor natrual-numbers-of
    :writer set-natrual-numbers-for
    :reader get-natrual-numbers-of)))

(cl-defmethod set-natrual-numbers-for ((instance myclass) value)
  (dolist (num value)
    (unless (and (integerp num)
                 (>= num 0))
      (error "Not natrual number: %d" num)))
  (setf (natrual-numbers-of instance) value))

(setq myinstance (myclass :natrual-nambers '(1 2 3 4 5)))

(setf (natrual-numbers-of myinstance) '(-1 -2 -3)) ;; 这就不好

(set-natrual-numbers-for myinstance '(-1 -2 -3)) ;; 会报错
(set-natrual-numbers-for myinstance '(1 2 3)) ;; 没问题

#2

对于 accessor 你可以

(cl-defmethod (setf natrual-numbers-of) :before ((instance myclass) value) ...)

然后我在上个贴子提了 (satisfies fn) 的用法,你一定沒仔细看。

(cl-deftype h-list (type)
  `(satisfies (lambda (x)
                (do ((lst x (cdr lst))
                     (res t))
                    ((or (eq lst nil) (eq res nil)) res)
                  (unless (typep (car lst) ,type)
                    (setq res nil))))))
(defclass myclass ()
  ((natual-numbers
    :initarg :natrual-nambers
    :accessor natrual-numbers-of
    :type (h-list '(integer 0)))))

(setf (natrual-numbers-of myinstance) '(-1 -2 -3)) 
;; Lisp error: (invalid-slot-type myclass natual-numbers (h-list '(integer 0)) (-1 -2 -3))

#3

我肯定仔细看了呀,只不过我这个问题重点在于对象没法控制外部对它的slot做什么,是例子没举好。


(你一打岔我都忘了)(setf natrual-numbers-of) 的原理是什么?只是cl-defmethod单纯支持这种写法吗?


#4

你沒法通過 defmethod 控制直接用 slot-value 來设置的,想「万无一失」只能用滥用类型檢查。

(setf (slot-value foo 'natual-numbers) -2)
;; 不会触发 (cl-defmethod (setf natrual-numbers-of) :before ...
;; 但仍会进行 type check
(macroexpand '(setf (natrual-numbers-of myinstance) '(-1 -2 -3)))
;; => (let* ((v myinstance)) (\(setf\ natrual-numbers-of\) (quote (-1 -2 -3)) v))

defun 也支持。 Common Lisp 里 defun 支持,然而 Emacs Lisp 要这樣写:

(defun \(setf\ foo\) (a b)
  (+ a 1))

(setf (foo 2) 3) ;; => 4

cl-defun 也不支持。


#5

为什么直接执行(setf natrual-numbers-of)没有返回lambda,而是报错了?


#6
  1. 你沒有 escape space。
  2. 你以為这是 lisp-1 啊?
(symbol-function '\(setf\ natrual-numbers-of\))
;; => #[642 ... byte-code

#7

喔!原来如此。话说lisp-1跟这个有什么关系?


#8

In NewLisp, which is a lisp-1 looks like Scheme (use this because it prints function definition):

(define (foo x) x))
foo
;; => (lambda (x) x)

where in Emacs Lisp

(defun foo (x) x)
(symbol-function 'foo)
;; => (lambda (x) x)

Languages like C, Ada, Python, JavaScript, Swift are all “lisp-1”。


是的


#9

喔喔,你是说我把函数symbol当成变量symbol eval了是吗。


thx