views:

65

answers:

2

I'm learning CL, and I have minimal experience in other languages. Could someone explain to me in layman terms what this means, especially what "out" here represents, and how it all fits together:

(defun save-db (filename)
  (with-open-file (out filename
                   :direction :output
                   :if-exists :supersede)
    (with-standard-io-syntax
      (print *db* out))))

Mostly, the bit I don't understand is "out", but an explanation of the whole thing would be nice.

Thanks

+5  A: 

out is the stream variable bound to the open file. with-open-file guarantees that the file is open inside the scope, and closed outside the scope, no matter how you exit.

ddyer
How can I get manpages describing such things on Linux for CL please?
agd
Manpages are a Unix tradition, and Lisp comes from a very distinct culture. In general, I google "hyperspec" + (whatever term I'm curious about).
Ken
Or, in many cases you can use Lisp's built-in doc system: `(documentation 'foo 'function)` will look up documentation for the function or macro `foo`. Sadly, this seems to be missing in SBCL for the specific case of `with-open-file`.
Owen S.
+1  A: 

As an addition to ddyer, you can also use MACROEXPAND or MACROEXPAND-1 to see what WITH-OPEN-FILE does:

(macroexpand '(with-open-file (out filename
                               :direction :output
                               :if-exists :supersede)
               (with-standard-io-syntax
                 (print *db* out))))

tells us

(LET ((OUT (OPEN FILENAME :DIRECTION :OUTPUT :IF-EXISTS :SUPERSEDE)) (#:G748 T))
  (UNWIND-PROTECT
      (MULTIPLE-VALUE-PROG1 (PROGN (WITH-STANDARD-IO-SYNTAX (PRINT *DB* OUT)))
        (SETQ #:G748 NIL))
    (WHEN OUT (CLOSE OUT :ABORT #:G748))))

We can see that we open the file called filename and assign that open file stream to out , and do something. Should something bad happen, UNWIND-PROTECT will CLOSE the stream, should it be non-nil.

The #:G748 variable is a GENSYMed symbol (so it's a fresh, uninterned, symbol). If nothing goes wrong writing the file, we set #:G748 to nil.

Thus, when we CLOSE the stream, if something went wrong #:G748 will be T, so CLOSE will attempt to clean up any side effects of having created the stream.

Frank Shearar