18. Globals
Valid global scope statements include:
Variable Declarations
Struct Declarations
Function and Procedure Declarations
Function and Procedure Prototypes
Typealias
All global statements are considered declarations.
Global statements must be written in dependency order, and this is a hard
requirement: a global may reference only symbols already defined earlier in
the file, so globals are initialized in the order they are written. A global
whose initializer references a global not yet defined at that point is
ill-formed and the
compiler must emit a SymbolError (see Errors).
const B = A; // A is not yet defined here -- ill-formed
const A = 10;
procedure main() returns integer { return 0; }
Errors
This program is ill-formed; the compiler must reject it (SymbolError).
Only global variable initializers are required to be written in dependency order. References between functions and procedures are not bound by textual order. Consult prototype for forward declaration rules in functions
A statement other than a declaration at global scope must emit a
GlobalError (see
Errors). An
assignment that targets a global from within a routine body instead an
AssignError (see Errors), as every global is const
(see below).
5 -> std_output; // a statement, not a declaration, at global scope
procedure main() returns integer { return 0; }
Errors
This program is ill-formed; the compiler must reject it (GlobalError).
18.1. Variable Declarations
In Gazprea values can be assigned to a global identifier. All
globals must be immutable (const). If a global identifier is declared
with the var specifier, then the compiler must emit a GlobalError
(see Errors). This restriction is in place since mutable global
variables would make functional purity undecidable in general.
var integer g = 0; // globals may not be declared 'var'
procedure main() returns integer { return 0; }
Errors
This program is ill-formed; the compiler must reject it (GlobalError).
Globals must always be initialized with a valid
constant expression. Unlike a local variable, a global is
never implicitly zero-initialized: a global declared
without an initializer is ill-formed, and the compiler must emit a
GlobalError (see Errors). If a zero-value is intended it
must be written explicitly (for example
const integer i = 0; or const integer[3] a = 0;). A global
initializer may reference other globals and use arithmetic and constexpr
aggregates, but it must be fully evaluable by the compiler before the
program runs. As a consequence:
Functions, procedures, and I/O operations may not appear in a global’s initializer.
A global
vectororstringis permitted only when it isconstwith aconstexprinitializer, its length is fixed at compile time, so aconstvector is equivalent to an array the size of its initializer. Consequentlyconst string s = "hi";andconst vector<integer> v = [1, 2, 3];are legal globals. An inferred-size array such asconst integer[*] X = [1, 2, 3]is likewise permitted if the initializer is a constexpr (see Sizing).
Legal globals in dependency order – a later global may read an earlier one:
const A = 10;
const B = A * 2; // may reference an earlier global
const integer[*] X = [1, 2, 3];
procedure main() returns integer {
B -> std_output; '\n' -> std_output;
X -> std_output;
return 0;
}
Output
20
[1 2 3]
The compiler must emit a GlobalError (see Errors) for any
violation of the above rules. For instance, a global with no initializer:
const integer i; // a global is never implicitly zero-initialized
procedure main() returns integer { return 0; }
Errors
This program is ill-formed; the compiler must reject it (GlobalError).
lemma: All globals are
constexpr.