Skip to main content

with-standard-io-syntax

with-standard-io-syntax Macro

Syntax:

with-standard-io-syntax {form}* → {result}*

Arguments and Values:

forms—an implicit progn.

results—the values returned by the forms.

Description:

Within the dynamic extent of the body of forms, all reader/printer control variables, including any implementation-defined ones not specified by this standard, are bound to values that produce standard read/print behavior. The values for the variables specified by this standard are listed in Figure 23–1.

|Variable Value|

| :- |

|

*package* The CL-USER package

*print-array* t

*print-base* 10

*print-case* :upcase

*print-circle* nil

*print-escape* t

*print-gensym* t

*print-length* nil

*print-level* nil

*print-lines* nil

*print-miser-width* nil

*print-pprint-dispatch* The standard pprint dispatch table *print-pretty* nil

*print-radix* nil

*print-readably* t

*print-right-margin* nil

*read-base* 10

*read-default-float-format* single-float

*read-eval* t

*read-suppress* nil

*readtable* The standard readtable

|

Figure 23–1. Values of standard control variables

Examples:


(with-open-file (file pathname :direction :output)
(with-standard-io-syntax
(print data file)))
;;; ... Later, in another Lisp:
(with-open-file (file pathname :direction :input)
(with-standard-io-syntax
(setq data (read file))))


*∗***read-base***∗ Variable*

Value Type:

a radix .

Initial Value:

10.

Description:

Controls the interpretation of tokens by read as being integers or ratios.

The value of *read-base*, called the current input base, is the radix in which integers and ratios are to be read by the Lisp reader . The parsing of other numeric types (e.g., floats) is not affected by this option.

The effect of *read-base* on the reading of any particular rational number can be locally overridden by explicit use of the #O, #X, #B, or #nR syntax or by a trailing decimal point.

Examples:

(dotimes (i 6)
(let ((\*read-base\* (+ 10. i)))
(let ((object (read-from-string "(\\DAD DAD |BEE| BEE 123. 123)")))
(print (list \*read-base\* object)))))
▷ (10 (DAD DAD BEE BEE 123 123))
▷ (11 (DAD DAD BEE BEE 123 146))
▷ (12 (DAD DAD BEE BEE 123 171))
▷ (13 (DAD DAD BEE BEE 123 198))
▷ (14 (DAD 2701 BEE BEE 123 227))
▷ (15 (DAD 3088 BEE 2699 123 258))
→ NIL

Notes:

Altering the input radix can be useful when reading data files in special formats.

Expanded Reference: with-standard-io-syntax​

Basic usage​

with-standard-io-syntax establishes a dynamic environment where all reader and printer control variables are bound to their standard values. This guarantees portable, reproducible read/print behavior.

(with-standard-io-syntax
(list *read-base*
*read-default-float-format*
*read-eval*
*read-suppress*
*print-base*
*print-case*))
=> (10 SINGLE-FLOAT T NIL 10 :UPCASE)

Ensuring round-trip consistency for data serialization​

The primary use case is to ensure that objects printed under standard syntax can be read back reliably, even if the surrounding environment has customized reader/printer settings.

;; Even with a modified environment, with-standard-io-syntax
;; ensures standard behavior for serialization
(let ((*print-base* 16)
(*read-base* 16))
(with-standard-io-syntax
(let ((str (prin1-to-string 255)))
(list str (read-from-string str)))))
=> ("255" 255)

Writing and reading data files​

A common pattern is to use with-standard-io-syntax when writing data to a file and reading it back, ensuring the data survives across different Lisp sessions with potentially different settings.

;; Writing data
;; (with-open-file (out pathname :direction :output)
;; (with-standard-io-syntax
;; (print data out)))

;; Reading data back
;; (with-open-file (in pathname :direction :input)
;; (with-standard-io-syntax
;; (setq data (read in))))

;; Simulated with string streams:
(let ((data '(hello 42 "world" 3.14)))
(let ((str (with-standard-io-syntax
(prin1-to-string data))))
(with-standard-io-syntax
(read-from-string str))))
=> (HELLO 42 "world" 3.14)
=> 62

The readtable is bound to the standard readtable​

Inside with-standard-io-syntax, *readtable* is bound to the standard readtable, so any custom reader macros in effect outside the form are not active.

(let ((*readtable* (copy-readtable)))
(set-macro-character #\!
(lambda (s c) (declare (ignore s c)) 'bang))
;; Inside with-standard-io-syntax, ! is a normal constituent
(with-standard-io-syntax
(with-input-from-string (s "!test")
(symbol-name (read s)))))
=> "!TEST"

Package is bound to CL-USER​

Inside the form, *package* is bound to the CL-USER package.

(in-package :cl-user)
(with-standard-io-syntax
(package-name *package*))
=> "COMMON-LISP-USER"