On Wed, 05 Jan 2011 16:17:09 +0100, Didier Verna said:
Until now, I've been uncounsiously relying on something that the standard does not seem to specify: the fact that shared slots equipped with an initform are initialized before the first instance is created:
(defclass test () ((slot :allocation :class :initform t)))
(defmethod initialize-instance :before ((test test) &key) (format t "Slot boundp: ~A~%" (slot-boundp test 'slot)))
- (make-instance 'test)
Slot boundp: T
- (make-instance 'test)
Slot boundp: T
I just realized that because with ABCL (and contrary to the other implementations I've tried), the result is NIL, and then T.
But now, I'm a little confused. Section 7.1.3 of CLHS says:
An :initform form is used to initialize a slot only if no initialization argument associated with that slot is given as an argument to make-instance or is defaulted by :default-initargs.
So after re-reading this (the "only" part notably), it now appears to me somewhat abusive to initialize shared slots earlier than at first instance creation time (like most lisps seem to do), because there's no way to know, at that time, whether the fist call to make-instance will provide an initarg.
WDYT?
The initarg will always set the slot anyway, so the only difference is that it has the "wrong" value transiently.
Related to this is a question of style as well. I rarely use shared slots, but until now, I thought of it as a convenient way to encapsulate information that's supposed to be used by instances only (including the first one). Maybe this is not a good idea after all...
Overall, I think shared slots are a bad idea. As discussed in a previous topic, defclass by itself doesn't provide very good encapsulation.
Another gotcha is that reevaluating a defclass with a different value for the initform doesn't reinitialize the slot.