Reputation: 105
either I'm missing something very stupid or the scope of special variables is unexpectedly different for defmethod and defun (tested using SBCL 1.1.14):
As expected:
(defun ttprint-object (prefix out)
(format out "~A: in defun: < ~A >~%" prefix *print-readably*))
(let ((*print-readably* t))
(format t "let: calling defun: < ~A >~%" *print-readably*)
(ttprint-object "from let" t))
let: calling defun: < T >
from let: in defun: < T >
With let defmethod works different from defun, so unexpected:
(defclass empty () ())
(defmethod print-object ((self empty) out)
(format out "in defmethod: < ~A >~%" *print-readably*)
(ttprint-object "from defmethod" out))
(let ((*print-readably* t))
(ttprint-object "from let" t)
(format t "let: calling defmethod: < ~A >~%" *print-readably*)
(format t "let: ~A" (make-instance 'empty)))
from let: in defun: < T >
let: calling defmethod: < T >
let: in defmethod: < NIL >
from defmethod: in defun: < NIL >
Also with setf defmethod works different from defun but same as with let:
(progn
(setq *print-readably* t)
(ttprint-object "from setf" t)
(format t "setf: calling defmethod: < ~A >~%" *print-readably*)
(format t "setf: ~A" (make-instance 'empty)))
from setf: in defun: < T >
setf: calling defmethod: < T >
setf: in defmethod: < NIL >
from defmethod: in defun: < NIL >
Hopefully it's me...
Thanks in advance, Frank
Upvotes: 2
Views: 270
Reputation: 85813
~A
binds *print-readably*
to false (emphasis added):
22.3.4.1 Tilde A: Aesthetic
An arg, any object, is printed without escape characters (as by princ). If arg is a string, its characters will be output verbatim. If arg is nil it will be printed as nil; the colon modifier (~:A) will cause an arg of nil to be printed as (), but if arg is a composite structure, such as a list or vector, any contained occurrences of nil will still be printed as nil.
…
~A
binds*print-escape*
to false, and*print-readably*
to false.
When you do
(format t "let: ~A" (make-instance 'empty))
the ~A
directive binds *print-readably*
to false (i.e., nil
), and eventually the Lisp writer calls the print-object
method for the object. If you don't want this binding, you might try ~W
which doesn't modify the printer variables:
22.3.4.3 Tilde W: Write
An argument, any object, is printed obeying every printer control variable (as by write). In addition, ~W interacts correctly with depth abbreviation, by not resetting the depth counter to zero. ~W does not accept parameters. If given the colon modifier, ~W binds
*print-pretty*
to true. If given the at-sign modifier, ~W binds*print-level*
and*print-length*
to nil.~W provides automatic support for the detection of circularity and sharing. If the value of
*print-circle*
is not nil and ~W is applied to an argument that is a circular (or shared) reference, an appropriate #n# marker is inserted in the output instead of printing the argument.
If you use ~W
, you get the results you'd originally expected:
CL-USER> (let ((*print-readably* t))
(ttprint-object "from let" t)
(format t "let: calling defmethod: < ~A >~%" *print-readably*)
(format t "let: ~w" (make-instance 'empty)))
from let: in defun: < T >
let: calling defmethod: < T >
let: in defmethod: < T >
from defmethod: in defun: < T >
Upvotes: 8