Lisp: how to create a temporary specialization of a method within a scope

In common lisp: override an existing function within scope? The OP requested something similar. But I want to create a specialized method, not a function. Suppose the method is defined as follows:

defmethod my-meth ((objA classA) (objB classB)) (...) 

What I would like to do is (pseudo-code):

 (labels ((my-meth ((objA classA) (objB (eql some-object))))) do stuff calling my-meth with the object...) 

The real use is that I want to create a temporary environment where setf slot-value-using-class will specialize in eql , essentially creating a specific object on demand, intercepting its record in slots. (The goal is to write down the old and new values ​​of the slots somewhere, and then call the next method.) I do not want to create a metaclass, because I can intercept already created instances of standard objects.

Of course, I tried this, and it did not work (because how are you DEFMETHOD in LABELS ?), But I wanted more experienced people to make sure that it was impossible to do this in the same way and / or suggest a suitable way.

Comments?

EDIT:

Daniel and Terrier provide excellent links to expand my knowledge of the possibilities, but I want to push him a little to find a more vanilla approach before heading there. I was exploring the possibility of adding a method upon entering an environment that will specialize in eql and executing the remove method upon exiting. I have not finished yet. If someone played with them, comments would be nice. Will keep the stream up to date.

EDIT 2: I try to do this using the add-method, but there is a problem. Here is what I tried:

  (defun inject-slot-write-interceptor (object fun) (let* ((gf (fdefinition '(setf sb-mop:slot-value-using-class))) (mc (sb-mop:generic-function-method-class gf)) (mc-instance (make-instance (class-name mc) :qualifiers '(:after) :specializers (list (find-class 't) (find-class 'SB-PCL::STD-CLASS) (sb-mop::intern-eql-specializer object) (find-class 'SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION)) :lambda-list '(new-value class object slot) :function (compile nil (lambda (new-value class object slot) (funcall fun new-value class object slot)))))) (add-method gf mc-instance) (defun remove-slot-write-interceptor () (remove-method gf mc-instance)) )) (defun my-test (object slot-name data) (let ((test-data "No results yet") (gf (fdefinition '(setf sb-mop::slot-value-using-class)))) (labels ((show-applicable-methods () (format t "~%Applicable methods: ~a" (length (sb-mop:compute-applicable-methods gf (list data (class-of object) object (slot-def-from-name (class-of object) slot-name))))))) (format t "~%Starting test: ~a" test-data) (show-applicable-methods) (format t "~%Injecting interceptor.") (inject-slot-write-interceptor object (compile nil (lambda (abcd) (setf test-data "SUCCESS !!!!!!!")))) (show-applicable-methods) (format t "~%About to write slot.") (setf (slot-value object slot-name) data) (format t "~%Wrote slot: ~a" test-data) (remove-slot-write-interceptor) (format t "~%Removed interceptor.") (show-applicable-methods) ))) 

A call (my-test) with some object slot and data as arguments results in:

 Starting test: No results yet Applicable methods: 1 Injecting interceptor. Applicable methods: 2 About to write slot. Wrote slot: No results yet <----- Expecting SUCCESS here.... Removed interceptor. Applicable methods: 1 

So, I'm stuck here. Specialization works because applicable methods now include the eql-special: after method, but unfortunately it does not seem to be called. Can anyone help, so I can finish with it and reorganize it into a sweet little utility macro?

+6
source share
2 answers

No, you cannot define a specialized method with dynamic degree or lexically limited coverage in Common Lisp.

Aspect-oriented programming can be used as an approach to solving the main problem. See Also Context-Oriented Programming .

ContextL is a library that provides aspect / context-oriented extensions for Common Lisp / CLOS.

An easy alternative is to use a special / dynamic variable that indicates when the method should log:

 (defparameter *logging* NIL "Bind to a true value to activate logging") (defmethod my-meth :around ((objA classA) (objB (eql some-object))) (prog2 (when *logging* (logging "Enter my-meth")) (call-next-method) (when *logging* (logging "Exit my-meth")))) (let ((*logging* T)) (do stuff calling my-meth with the object...)) 

Note that the: around method will also be called when the log is turned off.

+5
source

It seems that special forms of generic-flet and generic-labels were proposed for Common Lisp, but they were removed from the final specifications because they were considered to be rarely supported by implementations and poorly designed. See GENERIC-FLET-POORLY-DESIGNED Writeup Problem in HyperSpec. It is interesting to read the discussion of why people thought lexical methods were less useful than lexically restricted functions.

So, without them, I really don’t think there is a way to create a lexically restricted method, although I did not play with ContextL, which Terje is connected to in another answer, so it is possible that it will provide you with what you need.

+3
source

Source: https://habr.com/ru/post/886799/


All Articles