That sounds like a good way for it to work.
I'm not sure how safe it would be to depend on each of the extant implementation of Common Lisp to do this. It would probably be best if they all conformed; the only drawback would be the tiny possibility that some code somewhere is depending on the existing behavior. One could always use the old trick of having a compatibility mode for the sake of applications that want to move to the new release but whose developers don't have time to fix the application "the right way".
-- Dan
Pascal Costanza wrote:
On 6 Jan 2011, at 18:03, Didier Verna wrote:
Daniel Weinreb wrote:
This conversation has been good.
Yup. Here's what I gather from it, mostly:
- a shared slot's initform is required to be evaluated when the class is
created,
I agree here.
- however, nothing tells us that the resulting value is used immediately
to initialize the slot (it could just be stored somewhere), and implementations seem to be free to do so right now, or later when the first instance is created.
I disagree here. I think the only valid time to initialize a shared slot is when the first instance of the class in question is initialized, using either an explicitly passed value via an :initarg or :default-initargs option, or using the most recently provided :initform. What the CLOS MOP says about class-prototype is not binding in this case, according to the HyperSpec the only way to initialize instances of user-defined classes is by way of initialize-instance, reinitialize-instance and/or shared-initialize. This usually happens implicitly as an effect of calling make-instance.
This effectively means the following:
When a class is defined for the first time, the :initform for a shared slot needs to be evaluated immediately, and its result must be stored in some temporary memory location. (There is no notion of first-class dynamic environments in Common Lisp, so there is no other way of ensuring that the :initform can be evaluated in the correct dynamic environment.)
When a class is redefined before the first instance of that class is initialized, the :initform for a shared slot needs to be reevaluated and the result stored in that temporary memory location, possibly overriding a previously stored result of an initform.
When a class is redefined after the first instance of that class is initialized, the :initform for a shared slot can be ignored, because that shared slot is already initialized.
When the first instance of a class is initialized, the shared slots can be initialized with the values stored in the temporary memory locations for the results of the initforms, which can in turn be discarded.
So, effectively, a shared slot behaves like defparameter before the first instance of a class is initialized, and like defvar afterwards. This is pretty insane. It would have been easier and more straightforward if there had been a :reinitialize slot option for shared slots which, if true, makes it behave like defparameter, and if false, makes it behave like defvar. That would have been unambiguous semantics.
There is no real advantage in having shared slots over global special variables. On top of that, the slot access protocols in the CLOS MOP also don't work that well in conjunction with shared slots. So it's better to avoid them. Fortunately, this is the only feature in CLOS that doesn't make any sense, as far as I can tell.
Pascal