5. Declarations

Variables must be declared before they are used. Aside from a few special cases, declarations have the following formats:

[<qualifier>] [<type>] <identifier> [= <expression>];

A declaration creates a variable with an identifier of <identifier>, with type <type>, and optionally a type qualifier of <qualifier>. Optionally, a declaration may explicitly initialize the value of the new variable with the value of <expression>.

The two qualifiers are var and const, which qualify the identifier as mutable or immutable, respectively. In Gazprea if the optional qualifier is omitted the default is const, i.e. variables are immutable by default (see Type Qualifiers).

Both <qualifier> and <type> are optional, but at least one must be present so that the declaration can be told apart from an assignment. When <type> is elided it is inferred from <expression>, which must therefore be present and have an inferable type; if the type cannot be inferred the compiler must emit a TypeError (see Type Inference and Errors). When <qualifier> is elided it defaults to const as described above.

In Gazprea all variables must be initialized in a well-defined manner in order to ensure functional purity. Gazprea therefore follows a strict RAII-style discipline: every declaration is also an initialization, and no variable is ever observable in an uninitialized state. When the programmer omits the explicit initializer, the compiler implicitly initializes the variable to the zero value of its type. The zero value is 0 for integer, 0.0 for real, false for boolean, '\0' (the null character) for character, the empty collection (e.g. the empty string "") for a vector or string, and, for a fixed-size aggregate type (array, matrix, tuple, or struct), each element or field set to its own zero value. Gazprea has no null value. An array’s length is likewise settled at initialization and is then fixed for the remainder of the variable’s lifetime (see Sizing): an uninitialized array holds its declared number of elements, each set to the element type’s zero value. This applies to const declarations as well: a const variable declared without an initializer is legal and holds the zero value of its type permanently.

A declaration may appear at any point within a block before its first use. A previous version of the spec placed restrictions such that declarations could only appear at the start of a block, this restriction has been removed as of 2026.

A variable’s name enters scope only after its initializer has been evaluated. A program that refers to a variable within its own initialization statement is therefore ill-formed.

/* All of these declarations are illegal: the right-hand-side identifier
   is not yet in scope during its own initializer. */
integer i = i; // assuming that i is not initialized before this point
integer[10] v = v[1] * 2; // likewise v

Errors

This program is ill-formed; the compiler must reject it (SymbolError).

if a variable name is referenced in an initializer but is not defined in the current scope, the reference resolves as usual to the nearest enclosing-scope binding of that name, if one exists. Only when there is no such outer binding is this a reference to an undeclared variable, for which the compiler must emit a SymbolError (see Errors). So integer i = i; at the outermost scope is a SymbolError, whereas the same text nested inside a scope that already binds i legally reads the outer i. For instance:

integer x = 7;
if (true) {
  integer y = x;  /* y gets a value of 7 */
  real x = x; /* Refers to the enclosing scope's 'x', so this is legal */

}
/* Now 'x' refers to the integer version, with a value of 7 */

Likewise the following example would be legal, as gazprea allows for variable shadowing:

integer x = 7;
if (true) {
  var real x = x;  /* x gets a value of 7.0 */
  x = x + 1; // x -> std_output would print 8.0

}
/* Now 'x' refers to the integer version, with a value of 7 */

5.1. Special cases

Special cases of declarations are covered in their respective sections.

  1. Arrays

  2. Matrices

  3. Tuples

  4. Globals

  5. Functions

  6. Procedures