[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Attempting to circumvent Symbolics' Reader Method optimization
Hello SLUG,
I have written a piece of code that dependends on the reader methods to call
SLOT-VALUE. However, I have discovered that Symbolics' MOP performs an
optimization (?) that does not call SLOT-VALUE. I would like to circumvent
the "empty" creation of Reader Methods and place a real method (that calls
SLOT-VALUE in its place).
In the past week I have reviewed the following code:
1) for class creation
-- This lead me to the realization that although reader methods are created
they are not used by the reader generic function. Instead, slot access is
handled by the function CLOS-INTERNALS::STANDARD-CLASS-SHARED-SLOT-READER
(and is dispatched by: CLOS-INTERNALS::HANDLE-MISSED-DISPATCH).
2) for reader method creation and insertion
-- Here, I discovered the generic function COMPUTE-SLOT-METHODS, which is
called by the SHARED-INITIALIZE (STANDARD-CLASS) after method, creates
instances of STANDARD-READER-METHOD and adds the methods to the proper
reader generic function, using ADD-METHOD. This lead me to think that I
could write an after method for ADD-METHOD that would insert the proper
functional code.
3) for method creation
-- Here I discovered just how convoluted Symbolics' generic function/method
implementation is. The magical incantations that associate a real function
to a method and then the method to a generic function is distributed over
several files.
4) for generic function dispatching
-- I'm at a loss to figure out what's going on here.
My first attempt was to take the (empty) reader method and place a real function
in the function cell:
#|---------------------------------------------------------------------------------------------
CLOS:add-method (generic.function STANDARD-GENERIC-FUNCTION) [after Method]
(method STANDARD-READER-METHOD)
Argument List:
generic.function
method
Purpose: This method ensures that all QuasiObject reader methods call SLOT-VALUE.
Portability: WARNING -- This is a minor hack to the Symbolics implementation of CLOS. It
enforces the existance a real function in the reader method's of QuasiObjects.
|#;;;;;;;;
#+Symbolics
(defmethod CLOS:add-method :after ((generic.function STANDARD-GENERIC-FUNCTION)
(method CLOS:STANDARD-READER-METHOD))
(when (QO-Compatible-Class-p (first (CLOS:method-specializers method)))
(let ((function (CLOS-INTERNALS::make-standard-method-lambda
`(lambda (instance)
(slot-value instance ',(CLOS:method-slot-name method))))))
;; This uses some code found in the SHARED-INITIALIZE (STANDARD-METHOD) after method.
(setf (slot-value method 'CLOS-INTERNALS::function-parent)
`(method ,(CLOS:generic-function-name generic.function)
(,(class-name (first (CLOS:method-specializers method)))))
(SYS:function-name function)
method
(CLOS-INTERNALS::fdefinition-in-environment method NIL)
(compile NIL function)))
This never really did anything; which lead me to think that a lot more information/computation
was being used to "connect" the method's function to the method (and/or generic function).
I then try to get closer to what the DEFMETHOD macro (and CLOS-INTERNALS::DEFMETHOD-INTERNAL
function) were doing. Crucial to this was the use of the CLOS-INTERNALS::PARSE-METHOD
function. This was my second attempt:
#|---------------------------------------------------------------------------------------------
CLOS:add-method (generic.function STANDARD-GENERIC-FUNCTION) [around Method]
(method STANDARD-READER-METHOD)
Argument List:
generic.function
method
Purpose: This method ensures that all QuasiObject reader methods call SLOT-VALUE.
Portability: WARNING -- This is a minor hack to the Symbolics implementation of CLOS. It
enforces the existance a real function in the reader method's of QuasiObjects.
|#;;;;;;;;
#+Symbolics
(defmethod CLOS:add-method :around ((generic.function STANDARD-GENERIC-FUNCTION)
(method CLOS:STANDARD-READER-METHOD))
(if (QO-Compatible-Class-p (first (CLOS:method-specializers method)))
;THEN, make a new method to be added
(let ((name (list 'method (CLOS:generic-function-name generic.function) ()))
(form `(;;Specialized lambda list
((instance ,(class-name (first (CLOS:method-specializers method)))))
;;Method body
(slot-value instance ',(CLOS:method-slot-name method)))))
(flet ((finder (function.name lambda.list)
(declare (ignore lambda.list))
(let ((GF (ensure-generic-function function.name)))
(values GF (CLOS:class-prototype (CLOS:generic-function-method-class GF))))))
(call-next-method generic.function
(make-instance (CLOS:generic-function-method-class generic.function)
:SPECIALIZERS (CLOS:method-specializers method)
:LAMBDA-LIST '(instance)
:FUNCTION (compile NIL
(fifth (multiple-value-list
(CLOS-INTERNALS::parse-method
name form #'finder NIL #'warn))))
'CLOS-INTERNALS::no-next-method-information T))))
;ELSE
(call-next-method)))
Here, I tried to create a new method object to replace the useless one that was
initially passed to ADD-METHOD. This approach never really worked either.
Any ideas and/or approaches would be greatly appreciated.
-Bryan Basham
/-------------------------------------------------/
/ Bryan D. Basham /
/ NASA/JSC Mail Stop: ER22, Houston TX 77058 /
/ (713) 483-2065 /
/ Basham@AIO.JSC.NASA.GOV /
/-------------------------------------------------/