Whether slot types are being checked or not is undefined for both structures and CLOS instances.
Many implementations will do it for structures - but not all.
Few implementations will do it for CLOS instances - Clozure CL actually does it for example.
SBCL also can check CLOS slot types - when safety is high:
* (declaim (optimize safety))
NIL
* (progn
(defclass foo-class ()
((bar :initarg :bar
:type list)))
(make-instance 'foo-class :bar 'some-symb))
debugger invoked on a TYPE-ERROR: The value SOME-SYMB is not of type LIST.
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT] Exit debugger, returning to top level.
((SB-PCL::SLOT-TYPECHECK LIST) SOME-SYMB)
0]
How to do it otherwise?
This is kind of an advanced subject which probably needs some CLOS meta-object-protocol hackery. Two variants:
define a method for SHARED-INITALIZE which checks the init arguments.
define a metaclass for your class and a method on SET-SLOT-VALUE-USING-CLASS . But then you need to be sure that your implementation actually provides AND uses SET-SLOT-VALUE-USING-CLASS. This is a generic function, which is part of the MOP. Some implementations provide it, but some are only using it when requested (otherwise setting a slot may get a speed penalty).
For the latter here is self-built SBCL version to check types for writing slots:
First the metaclass:
; first a metaclass for classes which checks slot writes
(defclass checked-class (standard-class)
())
; this is a MOP method, probably use CLOSER-MOP for a portable version
(defmethod sb-mop:validate-superclass
((class checked-class)
(superclass standard-class))
t)
Now we check all slot writes for that metaclass:
; this is a MOP method, probably use CLOSER-MOP for a portable version
(defmethod (setf sb-mop:slot-value-using-class) :before
(new-value (class checked-class) object slot)
(assert (typep new-value (sb-mop:slot-definition-type slot))
()
"new value ~a is not of type ~a in object ~a slot ~a"
new-value (sb-mop:slot-definition-type slot) object slot))
Our example class uses that metaclass:
(defclass foo-class ()
((bar :initarg :bar :type list))
(:metaclass checked-class))
Using it:
* (make-instance 'foo-class :bar 42)
debugger invoked on a SIMPLE-ERROR in thread
#<THREAD "main thread" RUNNING {10005605B3}>:
new value 42 is not of type LIST
in object #<FOO-CLASS {1004883143}>
slot #<STANDARD-EFFECTIVE-SLOT-DEFINITION COMMON-LISP-USER::BAR>
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [CONTINUE] Retry assertion.
1: [ABORT ] Exit debugger, returning to top level.