The problem generally appears if I have a class containing, for example, a couple of slots that would be filled with vectors. If I want to make the object of this class more-or-less transparent, I implement print-object
for it. And here I am faced with the problem:
Here is the code. Consider two classes:
(defclass foo ()
((slot1 :initarg :slot1)
(slot2 :initarg :slot2)))
(defclass bar ()
((foo-slot :initarg :foo)))
And I have the following instances:
(defparameter *foo*
(make-instance 'foo
:slot1 '(a b c d e f g h i j k l m n o p q r s t u v)
:slot2 #(1 2 3 4 5 6 7 8)))
(defparameter *bar*
(make-instance 'bar
:foo *foo*))
What I want to see, is something like this:
> *bar*
#<BAR
foo-slot = #<FOO
slot1 = (A B C D E F G H I J K L M N O P Q R S T U V)
slot2 = #(1 2 3 4 5 6 7 8)>>
Definitions of print-object
for these classes can be something like these:
(defmethod print-object ((obj foo) out)
(with-slots (slot1 slot2) obj
(print-unreadable-object (obj out :type t)
(format out "slot1 = ~A slot2 = ~A" slot1 slot2))))
(defmethod print-object ((obj bar) out)
(with-slots (foo-slot) obj
(print-unreadable-object (obj out :type t)
(format out "foo-slot = ~A" foo-slot))))
However, their printable representation is less than ideal:
> *foo*
#<FOO slot1 = (A B C D E F G H I J K L M N O P Q R S T U V) slot2 = #(1 2 3 4 5
6 7 8)>
> *bar*
#<BAR foo-slot = #<FOO slot1 = (A B C D E F G H I J K L M N O P Q R S T U V) slot2 = #(1
2
3
4
5
6
7
8)>>
Using multiple line printing, I don't know how to control indentation:
(defmethod print-object ((obj foo) out)
(with-slots (slot1 slot2) obj
(print-unreadable-object (obj out :type t)
(format out "~%~Tslot1 = ~A~%~Tslot2 = ~A" slot1 slot2))))
(defmethod print-object ((obj bar) out)
(with-slots (foo-slot) obj
(print-unreadable-object (obj out :type t)
(format out "~%~Tfoo-slot = ~A" foo-slot))))
Thus, *foo*
prints OK, but *bar*
isn't:
> *foo*
#<FOO
slot1 = (A B C D E F G H I J K L M N O P Q R S T U V)
slot2 = #(1 2 3 4 5 6 7 8)>
*bar*
#<BAR
foo-slot = #<FOO
slot1 = (A B C D E F G H I J K L M N O P Q R S T U V)
slot2 = #(1 2 3 4 5 6 7 8)>>
In the past I tried to play around with print-indent
, but without a success (I couldn't see any effect from it, maybe wasn't using it correctly, SBCL 1.2.14).
Is there a (preferably simple) way to solve this?
Try something like this (might require more polishing):
(defmethod print-object ((obj foo) out)
(with-slots (slot1 slot2) obj
(print-unreadable-object (obj out :type t)
(format out "~<~:_slot1 = ~A ~:_slot2 = ~A~:>" (list slot1 slot2)))))
(defmethod print-object ((obj bar) out)
(with-slots (foo-slot) obj
(print-unreadable-object (obj out :type t)
(format out "~<~:_foo-slot = ~A~:>" (list foo-slot)))))
It uses ~<
and ~:>
, which are format operations for logical blocks. Then it uses ~:_
, which is a conditional newline. You should read the relevant hyperspec section.