user1090362
user1090362

Reputation: 33

how understand :print-function in defstruct of common lisp

I am reading the book successful lisp, There is a example:

(defstruct (ship
              (:print-function
               (lambda (struct stream depth)
                 (declare (ignore depth))
                 (format stream "[ship ~A of ~A at (~D, ~D) moving (~D, ~D)]"
                         (ship-name struct)
                         (ship-player struct)
                         (ship-x-pos struct)
                         (ship-y-pos struct)
                         (ship-x-vel struct)
                         (ship-y-vel struct)))))
    (name "unnamed")
    player
    (x-pos 0.0)
    (y-pos 0.0)
    (x-vel 0.0)
    (y-vel 0.0))

How can i understand this part:

(lambda (struct stream depth)
                     (declare (ignore depth))

why declare to ignore the depth? I feel quite confused, why not write lambda as

(lambda (struct stream)
         .....)

Thanks

Upvotes: 3

Views: 1134

Answers (2)

Rainer Joswig
Rainer Joswig

Reputation: 139411

The Common Lisp standard says this:

If the :print-function option is used, then when a structure of type structure-name is to be printed, the designated printer function is called on three arguments:

  • the structure to be printed (a generalized instance of structure-name).
  • a stream to print to.
  • 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.

So it is a three argument function. We need to write a function which takes three arguments then.

As usual, if our code does not use all arguments, we can declare them to be ignored, so that the compiler will not print a warning. Here the user has not used the variable depth.

Example: in the following function it is not clear if we forgot to use b or if not using it is on purpose.

CL-USER 21 > (defun foo (a b)
               (list a))
FOO

CL-USER 22 > (compile 'foo)
;;;*** Warning in FOO: B is bound but not referenced
FOO

Now we can tell the compiler that we chose not to use b.

CL-USER 23 > (defun foo (a b)
               (declare (ignore b))
               (list a))
FOO

No warnings during compilation:

CL-USER 24 > (compile 'foo)
FOO
NIL
NIL

Upvotes: 6

jlahd
jlahd

Reputation: 6303

You cannot simply ignore arguments in Common Lisp - unlike, for example, javascript. That is, if you write a function such as

(defun foo (bar baz)
  (list bar baz))

you cannot call it with any other number of arguments:

(foo 'a 'b)     ; correct number of arguments
=> (a b)
(foo 'a)        ; too few arguments
=> error
(foo 'a 'b 'c)  ; too many arguments
=> error

As the printer functions are called with three arguments - the object, stream and depth - you must also define all printers with exactly three arguments. The declaration simply removes a warning message by indicating to the compiler you are intentionally leaving the parameter unused.

Upvotes: 5

Related Questions