Re: Question about call-next-method

"David McClain (as dbm at refined-audiometrics dot com)" <[email protected]>
Newsgroups gmane.lisp.lispworks.general
Message-ID <[email protected]>
You can clear up a lot of the mystery about how LW is doing things by simply doing a Macroexpand:

Take this dummy definition for a Method:

(defmethod xxx ((a integer)) (doit a))

Just a nonsense definition for use in Macroexpand. Now macroexpand it to see: (orange highlights show how and where CALL-NEXT-METHOD arises…)

(DSPEC:DEF #3=(METHOD XXX #1=(INTEGER))
  (EVAL-WHEN (:COMPILE-TOPLEVEL)
    (CLOS::RECORD-CLASS-POTENTIAL-ARGUMENTS 'XXX '#2=(A) '#1#)
    (COMPILER::SET-ARG-SPEC-FROM-LAMBDA-LIST 'XXX '#2#)
    (COMPILER::NOTE-FUNCTION-DEFINED-FN 'XXX))
  (DSPEC:CALL-WITH-DEFINING-LOCATION CLOS::LOAD-DEFMETHOD-M
                                     '(XXX NIL . #2#)
                                     '#1#
                                     #'(LAMBDA #4=(A)
                                         (DECLARE (SYSTEM::SOURCE-LEVEL #<EQ Hash Table{0} 801015EFFB>)
                                                  (LAMBDA-NAME #3#)
                                                  (LAMBDA-LIST . #4#)
                                                  (SYSTEM::FLAG :METHOD)
                                                  (SYSTEM::BOUND-TYPE INTEGER A)
                                                  (IGNORABLE A))
                                         (LET ((#6=#:G9529
                                                (LOCALLY (DECLARE (OPTIMIZE (SAFETY 0))) CLOS::*NEXT-METHODS*)))
                                           (LET ((#7=#:G9530 A))
                                             (FLET ((CALL-NEXT-METHOD (&OPTIONAL . #5=(#:G9531))
                                                      (DECLARE (SYSTEM::FLAG :CALL-NEXT-METHOD)
                                                               (OPTIMIZE
                                                                (SAFETY 0)
                                                                (DEBUG 0)
                                                                (FIXNUM-SAFETY 0)
                                                                (SPEED 3))
                                                               (IGNORABLE . #5#))
                                                      (SYSTEM::INTERNAL-IF (ZEROP (SYSTEM::ARGUMENTS-COUNT))
                                                                           (CLOS::CALL-NEXT-METHOD-WITH-ORIGINAL NIL
                                                                                                                 '#3#
                                                                                                                 #6#
                                                                                                                 NIL
                                                                                                                 #7#)
                                                                           (CLOS::CALL-NEXT-METHOD-WITH-ARGS (SYSTEM::ARGUMENTS-COUNT)
                                                                                                             '#3#
                                                                                                             #6#
                                                                                                             1
                                                                                                             NIL
                                                                                                             NIL
                                                                                                             . #5#))))
                                               (DECLARE (INLINE CALL-NEXT-METHOD))
                                               (FLET ((NEXT-METHOD-P () (NOT (NOT #6#))))
                                                 (DECLARE (INLINE NEXT-METHOD-P))
                                                 (PROGN (BLOCK XXX (DOIT A))))))))))

> On Nov 15, 2025, at 19:31, Edward Kiser (as edkiser at gmail dot com) <[email protected]> wrote:
> 
> Hello,
> 
> Can call-next-method be safely captured in a lambda and returned, to
> be replayed later? Will it retain the meaning it had when it was
> captured?
> 
> My testing in LispWorks suggests that it can be, but I want to know if
> I can always expect that to be the case or if I am accidentally
> relying on undefined behavior.
> 
> The Common Lisp HyperSpec says, "The function call-next-method has
> lexical scope and indefinite extent, and can only be used within the
> body of a method defined by a method-defining form."
> 
> There are various ways to interpret this. For example, it's possible
> that call-next-method is a global function with indefinite extent but
> that its meaning varies depending on which method is currently
> running, and if no method is running, it has no meaning. This would
> mean that if you wrote a method (call it "A") that returned (lambda ()
> (call-next-method)), or even just #'call-next-method, and later called
> that procedure when no method was running, it would fail -- and if you
> called it inside method "B" it would call B's next method instead of
> A's.
> 
> When it says "can only be used within the body," does that mean
> lexically within the body, or dynamically when the body is running, or
> both?
> 
> I am sort of hoping that (lambda () (call-next-method)) would capture
> whatever meaning call-next-method had when "lambda" created the
> function, and use that same meaning whenever the function was called.
> 
> An implementation could ensure this by using symbol-macrolet
> internally to define a different meaning for call-next-method for each
> method, because call-next-method would be replaced by the macro
> expander with whatever meaning it is supposed to have in that lexical
> environment.
> 
> (The AMOP book uses an "add-function-bindings" function which
> apparently adds the bindings to the lexical environment, but it
> doesn't say how "add-function-bindings" works.)
> 
> The reason I want to save the meaning of call-next-method and use it
> later is because I am doing continuation-passing-style with a
> trampoline, and I wanted to use the long form of
> define-method-combination to combine methods, and each method might
> want to bounce off the trampoline several times.
> 
> Also I am using "amb" and I would like it if I could use the saved
> lambdas more than once.
> 
> Sincerely,
> 
> Ed Kiser
> 
> ----
> 
> Experiment:
> 
> CL-USER 1 > (defclass jikken1 () ())
> #<STANDARD-CLASS JIKKEN1 40202ABAB3>
> 
> CL-USER 2 > (defclass jikken2 () ())
> #<STANDARD-CLASS JIKKEN2 40202AE86B>
> 
> CL-USER 3 > (defgeneric try-something (j))
> #<STANDARD-GENERIC-FUNCTION TRY-SOMETHING 4030031B24>
> 
> CL-USER 4 > (defmethod try-something ((j jikken1)) (format t "Hello 1 ~s!~%" j))
> #<STANDARD-METHOD TRY-SOMETHING NIL (JIKKEN1) 402037294B>
> 
> CL-USER 5 > (defmethod try-something :around ((j jikken1)) (lambda ()
> (call-next-method)))
> #<STANDARD-METHOD TRY-SOMETHING (:AROUND) (JIKKEN1) 4020374B93>
> 
> CL-USER 6 > (defmethod try-something ((j jikken2)) (format t "Hello 2 ~s!~%" j))
> #<STANDARD-METHOD TRY-SOMETHING NIL (JIKKEN2) 4020375A4B>
> 
> CL-USER 7 > (defmethod try-something :around ((j jikken2)) (lambda ()
> (call-next-method)))
> #<STANDARD-METHOD TRY-SOMETHING (:AROUND) (JIKKEN2) 40203768FB>
> 
> CL-USER 8 > (setq aa1 (try-something (make-instance 'jikken1)))
> #<anonymous interpreted function 4030000ABC>
> 
> CL-USER 9 > (setq aa2 (try-something (make-instance 'jikken2)))
> #<anonymous interpreted function 4030000D1C>
> 
> CL-USER 10 > (funcall aa1)
> Hello 1 #<JIKKEN1 4020019FA3>!
> NIL
> 
> CL-USER 11 > (funcall aa2)
> Hello 2 #<JIKKEN2 402001DFC3>!
> NIL
> 
> CL-USER 12 > (funcall aa1)
> Hello 1 #<JIKKEN1 4020019FA3>!
> NIL
> 
> _______________________________________________
> Lisp Hug - the mailing list for LispWorks users
> [email protected]
> http://www.lispworks.com/support/lisp-hug.html
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.