[closer-devel] c2mop:standard-class not used in lispworks
Piotr Wasik
piotr.wasik at gmail.com
Sun Nov 3 13:33:51 UTC 2013
Hi,
Thanks for your explanation. I do agree with your choice - built-in
performance optimisation over standardised MOP by default.
As of my specific problem, I did not write the code that calls MOP, it is
here:
https://github.com/erikg/ucw-core/blob/master/src/rerl/standard-component/standard-component.lispSearch
for slot-value-using-class and slot-boundp-using-class in this file.
It belongs to UCW library. It works fine in SBCL because SBCL uses 'native'
MOP, and I tried to run it in LispWorks. I do not deny it could be
rewritten to use more common slot-boundp and slot-value calls, but for now,
the simpler solution is to use c2mop:standard-class rather than
cl:standard-class. UCW uses its own standard-component-class so the price
in performance is already paid, as optimisations for standard-class you
mentioned are not used.
Cheers,
Piotr
2013/11/3 Pascal Costanza <pc at p-cos.net>
> 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/a8f8e5dd/attachment.html>
More information about the closer-devel
mailing list