From: Gilbert Baumann
Subject: DEFSTRUCT/print-function puzzle
Date: 
Message-ID: <ywbfso50f39z.fsf@rz114s1.rz.uni-karlsruhe.de>
Hi,

I did the following test:

  (defstruct (z (:constructor make-z (x y)) 
                (:print-function print-z))
    x y)
  
  (defun print-z (self sink depth)
    (write-string (format nil "[~D/~D " depth *print-level*) sink)
    (prin1 (z-x self) sink)
    (princ " " sink)
    (prin1 (z-y self) sink)
    (princ "]" sink))
  
  (defun test ()
    (print (list (lisp-implementation-type)
                 (lisp-implementation-version)))
    ;; print-level test
    (let ((*print-level* 2))
      (print (make-z 'foo (make-z 'bar (make-z 'baz (make-z 'quux nil))))))
    ;; print-circle test
    (let* ((*print-level* nil)
           (*print-circle* t)
           (last (make-z 'quux nil))
           (z (make-z 'foo (make-z 'bar (make-z 'baz last)))))
        (setf (z-y last) z)
        (print z))
    ;; dont confuse the user
    (values))

and get following results:

  ("CLISP" "1999-01-08 (January 1999)") 
  [1/2 FOO [2/2 BAR #]] 
  #1=[1/NIL FOO [2/NIL BAR [3/NIL BAZ [4/NIL QUUX #1#]]]]
  
  ("CMU Common Lisp"
   "CMU Common Lisp 18a+ release x86-linux 2.4.5 29 June 1998 cvs libc5") 
  [0/2 FOO [0/2 BAR [0/2 BAZ [0/2 QUUX NIL]]]] 
  #1=[0/NIL FOO#2= [0/NIL BAR#2#[0/NIL BAZ#2#[0/NIL QUUX#2##1##3=]#3##3##3#
  
  ("Allegro CL Trial Edition" "5.0 [Linux/X86] (8/29/98 10:36)") 
  [0/2 FOO [0/2 BAR [0/2 BAZ [0/2 QUUX NIL]]]] 
  #2=[0/NIL FOO#1= [0/NIL BAR#1#[0/NIL BAZ#1#[0/NIL QUUX#1##2##3=]#3##3##3# 
  
  ("LispWorks Personal Edition" "4.1.16 Beta") 
  [0/2 FOO [0/2 BAR [0/2 BAZ [0/2 QUUX NIL]]]] 
  #1=[0/NIL FOO #2=[0/NIL BAR #3=[0/NIL BAZ #4=[0/NIL QUUX #1#]]]]
  
  ("Kyoto Common Lisp" "GCL-2-2.2000000000000002") 
  [0/2 FOO [0/2 BAR [0/2 BAZ [0/2 QUUX NIL]]]]
  #0=[0/NIL FOO #0=[0/NIL BAR #0= [... ad infinitum]
  Error: Bind stack overflow.

However CLHS says under defstruct / :print-function:

| If the :print-function option is used, [...], the designated printer
| function is called on three arguments:
|   - [...]
|   - [...]
|   - an integer indicating the current depth. The magnitude
|     of this integer may vary between implementations;
|     however, it can reliably be compared against
|     *print-level* to determine whether depth abbreviation is
|     appropriate.

This seems only be true for CLISP.

Further below it says:

| When *print-circle* is true, a user-defined print function
| can print objects to the supplied stream using write, prin1,
| princ, or format and expect circularities to be detected and
| printed using the #n# syntax.

This fails in GCL and is (human) readable in CLISP only.

So my question to the audience is: Why fail four of five implementations
the print-level test? Do they fail or is my reading of the CLHS a bit
too naive? Finally: What is the advertised way to implement portable
depth abbreviation in structure printers?

Gilbert.

-- 
;;; You know you have hacked Lisp too much, when you m-c-x in a C buffer.