Scope

Say we type the following,

> temp := 7;
> f := function(a,b)
> temp := a * b;
> return temp^2;
> end function;
If the evaluation process is now followed verbatim, the resultant context will look like [ (temp,7), (f,FUNC(a,b : 7 := a*b; return 7^2;)) ], which is quite clearly not what was intended!

Contents

Local Declarations

What is needed in the previous example is some way of declaring that an identifier, in this case temp, is a `new' identifier (i.e., distinct from other identifiers with the same name) whose use is confined to the enclosing function. Magma provides such a mechanism, called a local declaration. The previous example could be written,

> temp := 7;
> f := function(a,b)
> local temp;
> temp := a * b;
> return temp^2;
> end function;
The identifier temp inside the body of f is said to be `(declared) local' to the enclosing function. Evaluation of these two assignments would result in the context being [ (temp, 7), (f, FUNC(a,b : local temp := a*b; return local temp^2;)) ] as intended.

It is very important to remember that temp and local temp are distinct! Hence if we now type,

> r := f(3,4);
the resultant context would be [ (temp,7), (f,FUNC(a,b : local temp := a*b; return local temp^2;)), (r,144) ]. The assignment to local temp inside the body of f does not change the value of temp outside the function. The effect of an assignment to a local identifier is thus localized to the enclosing function.

The `first use' Rule

It can become tedious to have to declare all the local variables used in a function body. Hence Magma adopts a convention whereby an identifier can be implicitly declared according to how it is first used in a function body. The convention is that if the first use of an identifier inside a function body is on the left hand side of a :=, then the identifier is considered to be local, and the function body is considered to have an implicit local declaration for this identifier at its beginning. There is in fact no need therefore to declare temp as local in the previous example as the first use of temp is on the left hand side of a := and hence temp is implicitly declared local.

It is very important to note that the term `first use' refers to the first textual use of an identifier. Consider the following example,

> temp := 7;
> f := function(a,b)
> if false then
> temp := a * b;
> return temp;
> else
> temp;
> return 1;
> end if;
> end function;
The first textual use of temp in this function body is in the line
> temp := a * b;
Hence temp is considered as a local inside the function body. It is not relevant that the if false ... condition will never be true and so the first time temp will be encountered when f is applied to some arguments is in the line
> temp;
`First use' means `first textual use', modulo the rule about examining the right hand side of a := before the left!

Identifier Classes

It is now necessary to be more precise about the treatment of identifiers in Magma. Every identifier in a Magma program is considered to belong to one of three possible classes, these being:

(a)
the class of value identifiers
(b)
the class of variable identifiers
(c)
the class of reference identifiers

The class an identifier belongs to indicates how the identifier is used in a program.

The class of value identifiers includes all identifiers that stand as placeholders for values, namely:

(a)
all loop identifiers;
(b)
the $$ pseudo-identifier;
(c)
all identifiers whose first use in a function expression is as a value (i.e., not on the left hand side of an :=, nor as an actual reference argument to a procedure).

Because value identifiers stand as placeholders for values to be substituted during the evaluation process, they are effectively constants, and hence they cannot be assigned to. Assigning to a value identifier would be akin to writing something like 7 := 8;!

The class of variable identifiers includes all those identifiers which are declared as local, either implicitly by the first use rule, or explicitly through a local declaration. Identifiers in this class may be assigned to.

The class of reference identifiers will be discussed later.

The Evaluation Process Revisited

The reason it is important to know the class of an identifier is that the class of an identifier effects how it is treated during the evaluation process. Previously it was stated that the evaluation process was,

(1)
replace each identifier in the expression by its value in the current context.
(2)
simplify the resultant value to its canonical form.

Strictly speaking the first step of this process should read,

(1')
replace each free identifier in the expression by its value in the current context, where an identifier is said to be free if it is a value identifier which is not a formal argument, a loop identifier, or the $$ identifier.

This definition of the replacement step ensures for example that while computing the value of a function expression F, Magma does not attempt to replace F's formal arguments with values from the current context!

The `single use' Rule

As a final point on identifier classes it should be noted that an identifier may belong to only one class within an expression. Specifically therefore an identifier can only be used in one way inside a function body. Consider the following function,

> a := 7;
> f := function(n) a := a; return a; end function;
It is not the case that a is considered as a variable identifier on the left hand side of the :=, and as a value identifier on the right hand side of the :=. Rather a is considered to be a value identifier as its first use is as a value on the right hand side of the := (remember that Magma inspects the right hand side of an assignment, and hence sees a first as a value identifier, before it inspects the left hand side where it sees a being used as a variable identifier).
V2.28, 13 July 2023