.sr sect_type_set Section`13.5 .sr sect_library Section`4 .sr sect_semantics Section`3 .sr sect_expr Section`11 .sr sect_assign Section`9.2 .sr sect_except Section`12 .sr sect_module Section`13 .sr sect_mult_assn Section`9.2.2 . .chapter "Scopes, Declarations, and Equates" .para We now describe how to introduce and use constants and variables, and the scope of constant and variable names. Scoping units are described first, followed by a discussion of variables, and finally constants. .section "Scoping Units" .para Scoping units follow the nesting structure of statements. Generally, a scoping unit is a body and an associated "header". The scoping units are: .nlist From the start of a module to its end. .nnext From a cluster, proc, or iter to the matching end. .nnext From a then or else to the end of the corresponding body. .nnext From a for, do, or begin to the matching end. .nnext From a tag or others in a tagcase statement to the end of the corresponding body. .nnext From a when or others in an except statement to the end of the corresponding body. .nnext From the start of a type_set to its end. .end_list The last case above, the scope in a type_set, is a special case that will be discussed in sect_type_set. Whatever we say about scopes in the remainder of this section refers only to cases 1 through 6. .para The structure of scoping units is such that if one scoping unit overlaps another scoping unit (textually), then one is fully contained in the other. The contained scope is called a 2nested* scope, and the containing scope is called a 2surrounding* scope. .para New constant and variable names may be introduced in a scoping unit. Names for constants are introduced by equates, which are syntactically restricted to appear grouped together at or near the beginning of scoping units. For example, equates may appear at the beginning of a body, but not after any statements in the body. .para In contrast, declarations, which introduce new variables, are allowed wherever statements are allowed, and hence may appear throughout a scoping unit. Equates and declarations are discussed in more detail in the following two sections. .para In the syntax there are two distinct nonterminals for identifiers: 2idn* and 2name*. Any identifier introduced by an equate or declaration is an 2idn*, as is the name of the module being defined, and any operations it has. An 2idn* names a specific type or object. The other kind of identifier is a 2name*. A 2name* is used to refer to a subpiece of something, and is always used in context; for example, 2names* are used as record selectors. The scope rules apply only to 2idns*. .para The scope rules are very simple: .nlist An idn may not be redefined in its scope. .nnext Any idn that is used as an external reference in a _module may not be used for any other purpose in that module. .end_list Unlike other "block-structured" languages, CLU prohibits the redefinition of an identifier in a nested scope. An identifier used as an external reference names a module or constant; the reference is resolved using the compilation environment (see sect_library). .section "Variables" .para Objects are the fundamental "things" in the CLU universe; variables are a mechanism for denoting (i.e., naming) objects. This underlying model is discussed in detail in sect_semantics. A variable has two properties: its type, and the object that it currently denotes (if any). A variable is said to be 2uninitialized* if it does not denote any object. .para There are only three things that can be done with variables: .nlist New variables can be introduced. Declarations perform this function, and are described below. .nnext An object may be assigned to a variable. After an assignment the variable denotes the object assigned. Assignment is discussed in sect_assign. .nnext A variable may be used as an expression. The value of such an expression (i.e., the result of evaluating it) is the object that the variable denotes at the time the expression is evaluated. Expressions and their evaluation are described in sect_expr. .end_list .subsection "Declarations" .para Declarations introduce new variables. The scope of a variable is from its declaration to the end of the smallest scoping unit containing its declaration; hence, variables must be declared before use. .para There are two sorts of declarations: those with initialization, and those without. Simple declarations (those without initialization) take this form: .show .def decl "idn, etc : type_spec" .eshow A simple declaration introduces a list of variables, all having the type given by the type_spec. This type determines the types of objects that can be assigned to the variable. Here are some examples of simple declarations: .keep .show 4 i: int s(1)% declare i to be an integer variable i, j, k: chart(1)% declare i, j, and k to be character variables x, y: complext(1)% declare x and y to be complex number variables z: anyt(1)% declare z to be of type any; thus, z may denote any object .eshow .end_keep The variables introduced in a simple declaration initially denote no objects, i.e., they are uninitialized. Attempts to use uninitialized variables (if not detected at compiler-time) cause the run-time exception .show failure("uninitialized variable") .eshow (Exceptions are discussed in sect_except.) .subsection "Declarations with Initialization" .para A declaration with initialization combines declarations and assignments into a single statement. A declaration with initialization is entirely equivalent to one or more simple declarations followed by an assignment statement. The two forms of declaration with initialization are: .show idn : type_spec := expression .eshow and .show decl1, etc, decln := invocation .eshow These are equivalent to (respectively): .show 2 idn : type_spec idn := expression .eshow and .show 2 decl1 etc decln % declaring idn1 etc idn m idn1, etc, idnm := invocation .eshow In the second form, the order of the idns in the assignment statement is the same as in the original declaration with initialization. (The invocation must return 2n* objects; see sect_mult_assn). .para Here are some examples of declarations with initialization: .show 6 astr: array[string] := array[string]$create (1) s(1)% declare astr to be an array variable and initialize it to an empty array first, last: string, balance: int := acct$query (acct_no) t(1)% declare first and last to be string variables, balance an integer variable, t(1)% and initialize them to the results of a bank account query .eshow The above two statements are equivalent to the following sequences of statements: .show 6 astr: array[string] astr := array[string]$create (1) first, last: string balance: int first, last, balance := acct$query (acct_no) .eshow .section "Equates and Constants" .para An equate allows a single identifier to be used as an abbreviation for a constant that may have a lengthy textual representation. We use the term constant in a very narrow sense here: constants, in addition to being immutable, must be computable at compile-time. Constants are either types (built-in or user defined), or objects that are the results of evaluating constant expressions. (Constant expressions are defined below.) .end_list .para The syntax of equates is: .show 5 .long_def constant .def1 equate "idn = constant" .or "idn = type_set" .def1 constant type_spec .or "expression % the expression must be a constant expression" .eshow This section describes only the first form of equate; discussion of type_sets is deferred to sect_type_set. .para An equated identifier may be used as an expression. The value of such an expression is the constant to which the identifier is equated. An equated identifier may not be used as the target of an assignment. .para The scope of an equated identifier is the smallest scoping unit surrounding the equate defining it; here we mean the entire scoping unit, not just the portion after the equate. All the equates in a scoping unit must appear near the beginning of the scoping unit. The exact placement of equates depends on the containing syntactic construct; usually equates appear at the beginnings of bodies. .para Equates may be in any order within the group. Thus, forward references among equates in the same scoping unit are allowed, but cyclic dependencies are illegal. For example, .show 3 x = y y = z z = 3 .eshow is a legal sequence of equates, but .show 3 x = y y = z z = x .eshow is not. Since equates introduce idns, the scoping restrictions on idns apply (i.e., the idns may not be defined more than once). .subsection "Abbreviations for Types" .para Identifiers may be equated to type specifications, thus giving abbreviations for type names. For example: .show 7 at = array [int] ot = oneof [there: rt, null: null] rt = record [a: foo, b: bar] pt = proctype (int, int) returns (int) signals (overflow) it = itertype (int, int, int) yields (int) signals (bounds) seq = sequence mt = mark_table .eshow .para Notice that since equates may not have cyclic dependencies, directly recursive type specifications cannot be written. However, this does not prevent the definition of recursive types: clusters allow them to be written (see sect_module). .subsection "Constant Expressions" .para Here we define the subset of objects that equated identifiers may denote, by stating which expressions are constant expressions. (Expressions are discussed in detail in sect_expr.) A 2constant expression* is an expression that can be evaluated at compile-time to produce an immutable object of a built-in type. Specifically this includes: .nlist Literals. .nnext Identifiers equated to constants. .nnext Procedure and iterator names, including force [t] for any type t. .nnext Invocations of procedure operations of the built-in constant types (except string$s2ac), provided that all operands are constant expressions. .nnext Formal parameters. .end_list For completeness, here is a list of the built-in constant types: null, int, real, bool, char, string, oneof types, procedure types, and iterator types. We explicitly forbid applying any operations to formal parameters, since the values of formal parameters are not known at compile-time. .para Here are some examples of equates involving expressions: .show 13 hash_modulus = 29 pi = 3.14159265 win = true control_c = '\003' prompt_string = "Input: " nl = string$c2s ('\n') prompt = nl || prompt_string prompt_len = string$size (prompt) quarter = pi / 2.0 ftb = int$from_to_by ot = oneof [pair: cell, null: null] cell = record [first, second: int] nilptr = ot$make_null (nil) .eshow Note that the following equate is illegal because it uses a record constructor, which is not a constant expression: .show cell_1_2 = ot$make_cell (cell${first: 1, second: 2}) .eshow .para Any invocation in a constant expression must terminate normally; a program is illegal if evaluation of any constant expression would signal an exception. (Exceptions are discussed in sect_except.) Illegal programs will not be executed.