Skip to content
Special Variables and Dynamic Scope
step 1/5

Reading — step 1 of 5

Learn

~1 min readMacros and Special Forms

Common Lisp has TWO kinds of variable bindings:

Lexical (default with let):

(defvar count 10)

(defun inner () count)        ;; refers to lexical count if in scope

(let ((count 5))
    (inner))                   ;; — but lexical doesn't propagate to inner

If count is lexical, inner sees the global, not the inner binding.

Special / dynamic (declared with defvar or defparameter):

(defparameter *count* 10)     ;; *earmuffs* by convention for special vars

(defun inner () *count*)

(let ((*count* 5))             ;; rebinds the special variable
    (inner))                    ;; → 5 — inner sees the dynamic value

The * earmuffs convention marks special variables. Inside a let for a special variable, the binding is on a stack — visible to all callees, restored when the let exits.

declare special to make a single use special:

(let ((x 5))
    (declare (special x))
    (some-function))            ;; some-function sees this x dynamically

Use cases:

Configuration:

(defparameter *log-level* :info)

(defun log-msg (msg)
    (when (member *log-level* '(:debug :info))
        (format t "~a~%" msg)))

(let ((*log-level* :error))
    (log-msg "this won't print"))

Output redirection:

(defparameter *standard-output* ...)

(let ((*standard-output* (make-string-output-stream)))
    (do-something-that-prints)
    (get-output-stream-string *standard-output*))

The whole program's print calls now go to the string stream — without changing any code.

Database connection:

(defparameter *db* nil)

(defun execute (sql)
    (postmodern:query *db* sql))

(let ((*db* (connect ...)))
    (execute "..."))

Each thread / scope can have its own *db* without passing it as an argument.

defvar vs defparameter:

  • defvar — only sets if undefined (preserves existing value across reloads)
  • defparameter — always sets (reloading the file resets the value)

For true constants, use defconstant (signals an error on redefinition with a different value).

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…