

5.8.3 Scope and Extent

In the Librep by default variables have lexical scope. This means that bindings are associated with textual regions of programs, and may be accessed by any forms within this associated textual region. Moreover, the bindings are persistent, even when the flow of control is currently outside the associated region.

Consider the following example:

    ((counter 0))
  (defun count ()
    (setq counter (1+ counter))

the value of the counter variable persists, and is incremented each time the count function is called. The counter variable is accessible from nowhere but the forms written inside the let statement declaring it.

  ⇒ 1
  ⇒ 2

An alternative method of scoping variables is also available. Any variables declared using the defvar special form are said to be special variables, they have indefinite scope and dynamic extent, often simplified to dynamic scope. What this means is that references to these variables may occur anywhere in a program (i.e. bindings established in one function are visible within functions called from the original function) and that references may occur at any point in time between the binding being created and it being unbound. Special variables are stored in a separate namespace.

Dynamic scoping is easy to abuse, making programs hard to understand and debug. A quick example of the use of dynamic scope,

(defvar *foo-var* nil)

(defun foo (x)
      ;; a dynamically-scoped binding
      ((*foo-var* (* x 20)))
    (bar x)

(defun bar (y)
  ;; Since this function is called from
  ;; the function foo it can refer
  ;; to *foo-var*
  (setq y (+ y *foo-var*))

As shown in the previous example, a common convention is to mark special variables by enclosing their names within asterisks.

Function: special-variable-p symbol

Returns t if symbol is a special variable (dynamically scoped).
