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:
(let ((counter 0)) (defun count () (setq counter (1+ counter)) counter))
the value of the
counter variable persists, and is incremented
each time the
count function is called. The
variable is accessible from nowhere but the forms written inside the
let statement declaring it.
(count) ⇒ 1 (count) ⇒ 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
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) (let ;; a dynamically-scoped binding ((*foo-var* (* x 20))) (bar x) … (defun bar (y) ;; Since this function is called from ;; the function
fooit 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.
Returns t if symbol is a special variable (dynamically scoped).