2015年6月21日日曜日

SBCL での defclass slot の :type オプションの挙動


defclass の slot には、:type オプションを指定することができる。

期待としては、:type オプションを指定した場合、指定した型を満たさない値を代入しようとすると、エラーとなって欲しい。ところが、SBCL ではそのようにならない。

(defclass foo ()
  ((x :accessor foo-x
      :initarg :x
      :type integer)))

(let ((x (make-instance 'foo :x 1)))
  (setf (foo-x x) :foo)
  (foo-x x))                           ; => :foo

defclass と slot へのアクセスを optimize safety で評価すると、期待する挙動となる。

(locally (declare (optimize safety))
  (defclass foo ()
    ((x :accessor foo-x
        :initarg :x
        :type integer)))

  (let ((x (make-instance 'foo :x 1)))
    (setf (foo-x x) :foo)              ; error
    (foo-x x)))

CLHSには、以下のようにあるものの、

The consequences of attempting to store in a slot a value that does not satisfy the type of the slot are undefined.

その前の部分には以下のようにある。

The :type slot option specifies that the contents of the slot will always be of the specified data type.

SBCL User Manualには以下のようにあり、その理由は示されていない。悲しい。

Types declared using the :type slot option in defclass are asserted if and only if the class was defined in safe code and the slot access location is in safe code as well.