Previous chapter: Syntax and Semantics

Dylan manual: Variables

4. Variables

See Also: Dylan Design Notes: Definitions are Declarative (Change)

The following functions and syntax forms are used to define and manipulate variables. Additional information on module variables is given in the following section.

Throughout the text below, the term environment is used to refer to the set of variables that are available to a given part of a program. It includes both module variables and lexical variables.

Variables can be set to new values with the set! special form, which is described in a later section.

Module Variables

Module variables are created with the define syntax form and the related forms define-class, define-generic-function, define-method, and define-slot. Module variables can be referenced from anywhere inside the module. Source code is associated with a specific module through the programming environment. This association occurs at development time and cannot be changed at run-time.

See Also: Dylan Design Notes: Define Like Bind (Addition)

See Also:Dylan Design Notes: Defining Forms Make Constants (Change)

define[next citation]   variable-name initial-value   ==>  variable-name	[Macro]
define creates a variable accessible through variable-name in the current module FN9 . The initial-value argument provides the initial value of the variable.

The variable-name argument is not evaluated. It must be a symbol, or a list of the form (setter symbol).

The initial-value argument is evaluated, and the value is stored into the new variable.

See also the related forms define-class, define-generic-function, define-method, and define-slot.

 ? foo
 error: unbound variable foo
   ? (define foo 10)
   ? foo
   ? (+ foo 100)
   ? bar
   error: unbound variable bar
   ? (define bar foo)
   ? bar
   ? (define foo 20)
   warning: redefining variable foo
   ? foo
   ? bar
   ? (+ foo bar)
Lexical Variables

Lexical variables are visible within a limited piece of program text. Parameters of methods are lexical variables. Other lexical variables can be created with the syntax form bind. Several other syntax forms also create lexical variables as part of their operation.

bind[return to first citation]	((binding1 init1)	[Special Form]
	  (binding2 init2)...)
	form1 form2 ...
==>  values
binding may be one or more instances of either variable-name or

(variable-name type), optionally followed by #rest rest-variable-name.

bind creates a new lexical variable for each variable-name and rest-variable-name and executes the forms in an environment containing the new variables. Each init is evaluated in an environment containing the previously bound variable-names. The values of the last form are returned. If there are no forms, #f is returned.

The variables are initialized to values from the inits. In the simplest case, where there is only one variable-name for each init, the variable is bound to the value of the init. If there is more than one variable-name for a given init, the variables are bound to the multiple values returned by the init. The complete multiple-value semantics is described below.

? (bind ((number1 20))
          (number2 30))
    (+ number1 number2))
The inits are evaluated in order. Each init can refer to the variables that were bound to values from the previous inits.

? (bind ((x 20) (y (+ x x))) (+ y y)) 80 A variable shadows any module variable with the same name and any surrounding lexical variable with the same name. This rule means that the innermost version of a variable is the one referenced.

? (define foo 10)
? (+ foo foo)
? (bind ((foo 35))
    (+ foo foo))
? (bind ((foo 20))
    (bind ((foo 50))
      (+ foo foo)))
Checking Init Types

Each variable bound by bind can be a variable name or a list of the form (variable-name type). If the latter syntax is used, then the init must evaluate to a value of the given type, or an error is signaled.type-checking[next citation]

The type can be any form. It is evaluated before the corresponding init is evaluated. The type must evaluate to a class or a singleton. FN10

? (bind (((x <integer>) (sqrt 2)))
error: 1.4142135623730951 is not an instance of <integer>
Binding Multiple Values

bind can be used to receive multiple values. If there is more than one variable-name for a given init, the variables are bound to the multiple values returned by the init. If the init produces more values than there are variable-names, the extra values are ignored. If the init produces fewer values than there are variable-names, then the extra variables are bound to #f.

? (bind ((foo bar baz (values 1 2 3)))
    (list foo bar baz))
(1 2 3)
? (define-method opposite-edges ((center <number>)
                                 (radius <number>))
    (bind ((min max (edges center radius)))
      (values max min)))
? (opposite-edges 100 2)
Multiple values can be used to perform parallel binding, as performed by let in Lisp.

? (bind ((x 10)
         (y 20))
    (bind ((x y (values y x)))
      (list x y)))
(20 10)
The token #rest can be used in the variable lists. This use of #rest is roughly equivalent to its use in parameter lists. #rest is followed by a single variable name; all remaining multiple values are stored in a sequence, which becomes the value of the variable.

? (bind ((#rest nums (edges 100 2)))
(98 102)

Next chapter: Modules