[closer-devel] c2mop:standard-class not used in lispworks
Pascal Costanza
pc at p-cos.net
Sun Nov 3 00:15:55 UTC 2013
Hi,
Unfortunately, it’s not possible to fix this.
In Closer to MOP, I have to balance a couple of requirements, and I cannot fulfill them all.
In LispWorks, the default protocol for slot accesses is based on symbols, not on effective slot definition objects. (This is how the CLOS MOP draft specifications have been defined up until very late in the CLOS MOP specification process.)
So by default, you say something like (slot-value-using-class (find-class ‘foo) (make-instance ‘foo) ‘s1), which is understood by LispWorks’s CLOS implementation (or better yet, just the plain (slot-value (make-instance ‘foo) ’s1)).
The goal of Closer to MOP is to change the protocols so they are more in line with what the actual CLOS MOP specification says. In order to be able to do this, I have to provide two specializations on slot-value-using-class and friends. The first is a method that still dispatches on slot names that then calls slot-value-using-class again with the respective effective slot definition object. The method looks like this:
(cl:defmethod slot-value-using-class
((class standard-class) object (slot symbol))
(declare (optimize (speed 3) (debug 0) (safety 0)
(compilation-speed 0)))
(let ((slotd (find-slot slot class)))
(if slotd
(slot-value-using-class class object slotd)
(slot-missing class object slot 'slot-value))))
Now, I also need to define a method for effective slot definition objects, which is not provided by default in LispWorks, to make this all work. It looks like this:
(cl:defmethod slot-value-using-class
((class standard-class) object (slotd standard-effective-slot-definition))
(declare (optimize (speed 3) (debug 0) (safety 0)
(compilation-speed 0)))
(slot-value-using-class
(load-time-value (class-prototype (find-class 'cl:standard-class)))
object
(slot-definition-name slotd)))
By calling slot-value-using-class again on the slot name, but this time on the original cl:standard-class instead of Closer to MOP’s standard-class, I now get back the original LispWorks slot access.
I cannot specialize the first method on cl:standard-class. This doesn’t work, because the CLOS MOP specification explicitly requires that each user-defined method on the standard protocol generic functions must have at least one argument specialized on one’s own class. I don’t have a specific class for the second argument at all, and the third argument must be specialized on symbol, so what I’m left with is to specialize the first argument on c2cl:standard-class. The same holds for the second method: There is no specific specializer available for the second argument, and the third argument must be standard-effective-slot-definition. (It is imaginable that the third argument is a subclass of standard-effective-slot-definition, but that wouldn’t solve your issue either.)
If you think about it, it’s clear why the requirement of the CLOS MOP exists: If I were allowed to define methods on standard protocol functions that are specialized only on standard metaclasses, this would replace the default behavior of the CLOS implementation, and thus prevent CLOS from working at all.
One way out would be to “force” every class to be an instance of c2cl:standard-class instead of cl:standard-class, as you suggest. However, I decided against that because this would lead to a potentially severe performance overhead: CLOS implementations make a major effort to implement the protocols as efficiently as possible if only standard metaclasses are involved. However, c2cl:standard-class is not a standard metaclass, so the CLOS implementation would have to resort to much slower generic implementations of the protocols. I decided it to be more important that you get best performance for parts of the protocol that are not specialized in any way for your own metaclasses, and only have an impact on subprotocols that you effectively change, as much as possible.
If you subclass c2cl:standard-class, you get the ‘fixed’ protocols, but if you don’t, you get the default implementation of LispWorks (same for any other CL implementation, as far as possible).
Yes, this means that you sometimes run into issues like the one you report. But I believe this is a lower price to pay than trying to get performance back that you may have lost with a more general implementation.
For your specific problem: Why do you need to call slot-boundp-using-class manually yourself? This should normally not be required, it’s normally better to just call slot-boundp…
Pascal
On 2 Nov 2013, at 22:03, Piotr Wasik <piotr.wasik at gmail.com> wrote:
> Hi,
>
> I have tried the following in LispWorks:
>
> CL-USER 1 > (c2cl:defclass foo () ((s1)))
> #<STANDARD-CLASS FOO 201010AB>
>
> CL-USER 2 > (c2mop:slot-boundp-using-class (find-class 'foo) (make-instance 'foo) (first (harlequin-common-lisp:class-slots (find-class 'foo))))
>
> Error: The slot #<STANDARD-EFFECTIVE-SLOT-DEFINITION S1 23A4C803> is missing from #<FOO 23A4C2B7> (of class #<STANDARD-CLASS FOO 201010AB>)
>
> The thing is that specialisation defined in https://github.com/mcna/closer-mop/blob/master/closer-lispworks.lisp uses standard-class from c2mop, which is later exported, but nothing forces subsequent code to use it instead of cl:standard-class.
>
> Of course (eq (find-class 'cl:standard-class) (find-class 'c2mop:standard-class)) --> NIL
>
> When I explicitely use c2mop:standard-class however, the specialisation from closer-mop.lisp is used:
>
> (c2cl:defclass foo () ((s1)) (:metaclass c2mop:standard-class))
> (c2mop:slot-boundp-using-class (find-class 'foo) (make-instance 'foo) (first (harlequin-common-lisp:class-slots (find-class 'foo))))
> NIL
>
> As expected. How can it be fixed please? Is there any test suite that can check what other functionality is affected?
>
> Cheers,
> Piotr
--
Pascal Costanza
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/closer-devel/attachments/20131103/64323926/attachment.html>
More information about the closer-devel
mailing list