### 1.5.2. Indexing

To select a "subvalue" of a given multiple (i.e. a value which is a subset of that given multiple value), we use 'indexers'. The smallest subvalue is one individual element of the multiple, which is obtained by "subscripting". All other subvalues can be obtained by "trimming"; the mode of a subvalue thus obtained is some 'ROWS of MODE'.

#### 1.5.2.1. Indexers

An indexer consists of a sub-symbol "[", followed by one or more 'trimscripts' separated by comma-symbols followed by a bus-symbol "]" (see below). A trimscript is a trimmer-option (i.e. a 'trimmer' or EMPTY) or a 'subscript'. Examples:

<table><tr><td>[i]</td><td>[i,j]</td><td>[i,j,k]</td><td>i, j and k are subscripts;<br/>a subscript may be almost any unit<br/>yielding an integral value (see 5.5.1.3)</td></tr><tr><td>[i:j]</td><td>[h:j,i:k]</td><td></td><td>all i s and h s are lower-bounds,</td></tr><tr><td>[i:]</td><td>[:j,i:k]</td><td></td><td>all j s and k s are upper-bounds;</td></tr><tr><td>[:j]</td><td>[ ,i:k]</td><td></td><td>all such bounds must again yield</td></tr><tr><td>[ ]</td><td>[i: , :k]</td><td></td><td>integral values;</td></tr><tr><td>[ , ]</td><td></td><td></td><td>i:j, h:j, i:k etc. are trimmers</td></tr></table>

If a bound is omitted, then its value is that of the corresponding bound in the descriptor of the given multiple. If both bounds are omitted, then the colon may be omitted also.

Examples in which we find trimscripts of both kinds in an indexer are:

[h, i:j] [ ,k] [,,k]
[h, i:j, k] [ :h, i, k: ]

A special kind of a trimmer is a trimmer with a revised-lower-bound:

<table><tr><td>[i:j ath]</td><td>the lower-bound of the multiple subvalue</td></tr><tr><td>or or (in another notation)</td><td>trimmed by i:j gets a new value which</td></tr><tr><td>[i:j @h]</td><td>is the value of h; a revised-lower-bound</td></tr></table>

In the absence of a revised-lower-bound (but not when both bounds and the colon are omitted also), the multiple subvalue gets a revised lower-bound of 1.

Semantically, an indexer is pretty close to a descriptor. In fact, unless all
its trimscripts are subscripts, it describes a multiple (sub)value in much the same way that a descriptor does. We give two examples:

1.5.2.2. Subscripting

<figure><img src="image_59.png" /></figure>
### 1.5.2.3. Trimming

<figure><img src="image_60.png" /></figure>

### 1.5.3. Identifier declarations for multiples

We could discuss, systematically again, the three fundamental identity-declarations E1, E2 and E3 as elaborated for the general **amode** in Section 1.2, substituting now for **amode** all kinds of 'ROWS of MODE'. An exhaustive discussion would, however, be rather boring without giving substantially new information. We shall, therefore, confine ourselves to a brief survey of many possibilities and a few remarks on mixed matters.

(E3.1) $\mathbf{ref} [ \mathbf{amode} \mathbf{arrow} = \mathbf{loc} [m:n] \mathbf{amode} ;}$
↑                 ↑
formal-declarer   actual-declarer
or, as usual:

(E3.1*) [m : n] amode arow;

The identifier *arrow* will now yield the name referring to a row of *amodes*, the descriptor of which is [*m* : *n*].

(E3.2) ref [, ] amode arowrow = loc [*h* : *k*, *m* : *n*] amode ;

or:

(E3.2*) [*h* : *k*, *m* : *n*] amode arowrow ;

The identifier *arrowrow* will now yield the name referring to a row of *amodes*, the descriptor of which is [*h* : *k*, *m* : *n*].

In both declarations E3.1 and E3.2 a new multiple value will be generated
onto the stack; together with these multiple values, their descriptors will be
made.

E3.2 elaborates into:

<figure><img src="image_61.png" /></figure>

An example of an E1-type identity-declaration for multiples is:

(E1) [, ] amode multipleconstant = arowrow ;

in which the multiple value (and its descriptor) referred to by *arrowrow* is
ascribed to the identifier *multipleconstant*.
An example of an E2-type identity-declaration for multiples is:

(E2) `ref [] amode namultiple = arow;`

in which the name yielded by `arrow` is ascribed to the identifier `namultiple` (which is thus made to refer to the multiple value referred to by `arrow`).

By virtue of E1 you cannot assign to `multipleconstant` (being no name) and by virtue of E2 an assignation to `namultiple` results in assigning to `arrow`.

`namultiple &` or `arrow &` := `anotherow`

Here, `anotherow` must of course yield a `[] amode` value, but it must do more than that—the bounds must match also. The bounds of the location referred to by `arrow` (and so by `namultiple`) are `[m : n]`. Therefore the bounds of `anotherow` must be `[m : n]` also—otherwise it will not fit.

However, we can declare a “flexible” name to which the restriction does not apply:

(E3.3) `ref flex [] amode arowflex = loc flex [m : k] amode;`

or:

(E3.3*) `flex [m : k] amode arowflex;`

`arrowflex` is a flexible name, and its mode is `ref flex [] amode` (different from the mode of `arrow`). Now, when we assign

`arrowflex := anotherow`

it does not matter that `anotherow` has `n-m+1` elements and the location referred to by `arrowflex` has room for `k-m+1`. It is a flexible location and will be expanded or contracted to suit.

This flexible feature will, however, be an expensive luxury in some implementations. It presupposes a storage allocation regime in which multiples are allowed to “breathe”.

### 1.5.4. Slices

The external object which yields or refers to a subvalue of a multiple is the 'slice'; it consists of an identifier (yielding or referring to a multiple value) followed by an indexer:

<table><tr><td><code>arrow [i]</code></td><td>is an <b>amode</b> variable, <b>arrow</b> is subscripted</td></tr><tr><td><code>arrow [i:j]</code></td><td>is a <b>[] amode</b> variable, <b>arrow</b> is trimmed</td></tr><tr><td><code>arrowrow [i,j]</code></td><td>is an <b>amode</b> variable, <b>arrowrow</b> is subscripted</td></tr></table>
`arrowrow` [i, ] is a [ ] `amode` variable, `arrowrow` is subscripted and trimmed

`arrowrow` [i:j,p:q] is a [', ] `amode` variable, `arrowrow` is trimmed

All these slices yield (sub)names (by virtue of E3.1 and E3.2) and you may
assign to them (provided the bounds fit, of course).

`arow := arrowrow [i, ] ;`

`arrowrow [i:j,p:q] := anotherrowrow [h:k,r:s] ;`

`arowrow [i, ] := arow ;`

`arow := arrowrow [j, ]`

In an assignment like:

`arowflex := arow [i:j]`

nothing can go wrong, because `arowflex` is flexible. See 5.5.4 for full details
of such assignments.

Slices may also turn up in identity-declarations:

(E1.1) [ ] `amode` `rowcopy` = `arrowrow` [i, ]

A copy of the *i*th row of the multiple value referred to by *arrowrow* is
ascribed to *rowcopy* (this copy of a subvalue has got its own descriptor,
which is [*m* : *n*]).

(E1.2) `ref [ ] amode arowname = arrowrow [i, ]`

The name of the *i*th row of the multiple value referred to by *arrowrow* (for
which subname a new descriptor has been made) is ascribed to *arowname*.
The element:

`arrowrow` [i,j]

may now also be accessed by:

`arowname [j]`

Such identity-declarations are of the utmost importance in situations
where you want to have an efficient access to a multiple subvalue. For
applications see 8.5.3.

1.5.5. Interrogations

We already mentioned that its descriptor belongs to a multiple (sub)value
and that you have a certain access to it. Bounds of a flexible location, for
example, can be changed by assignation (see 5.5.4.1).

In a formal-row-of-MODE-parameter the lower- and upper-bounds do not have to be specified. In that case, you cannot in general know the bounds that will appear in the actual-row-of-MODE-parameter. For example, if you are in a routine, then you cannot know the actual bounds from the formal-parameter(s). For this purpose some standard operators, `lwb` and `upb`, are provided:

<table><tr><td>1 lwb arowrow</td><td>or</td><td>lwb arowrow</td><td>yields the first lower bound</td></tr><tr><td>2 upb arowrow</td><td></td><td></td><td>yields the second upper bound</td></tr></table>

For further details see 5.5.3 and 6.5.

**Vertical readers**, please turn to 2.5.

## 1.6. Unions

### 1.6.1. United modes

A MODE may be MOOD or UNITED. Thus far we have considered MOODs. Every MOOD defines a certain class of values. A UNITED mode does not define a new class of values.

If we declare:

(EO) mode abcmode = union ( amode , bmode , cmode );

then an `abcmode` is either an `amode` value or a `bmode` value or a `cmode` value. There is no such thing as an `abcmode` value. Nevertheless we shall bring an `abcmode` into our pictures in the following way:

abcmode

<figure><img src="image_62.png" /></figure>

In any given situation, one of the dotted lines will be thick (i.e. one of the possible modes in a union will be in force).
Unions “commute” and “associate”:

(E0.1) mode bacmode = union ( bmode , amode , cmode );

specifies the same united mode as abcmode.

(E0.2) mode abcmodedaemodeuv = union ( amode , bmode , cmode ,
union ( dmode , amode , emode ,
union ( umode ,
vmode ) ) );

specifies the same united mode as:

(E0.2*) mode abcdeuvmode = union ( amode , bmode , cmode , dmode , emode , umode , vmode );

Let there be declared:

amode maralyn, bmode marblyn, cmode marclyn;

1.6.1.1. United constants

Consider the identity-declaration:

(E1) abcmode marlyn = marblyn ;

it elaborates into:

<figure><img src="image_63.png" /></figure>

A copy of the bmode value referred to by marblyn is ascribed to the
identifier marlyn. Observe that marlyn is still an abcmode identifier, but she
now yields a bmode value (we say that bmode values are "acceptable" to the
mode abcmode).
When we declare:

(E1.2) `abcmode marlyn = maralyn;`

then she is made to yield an `amode` value, and in:

(E1.3) `abcmode marlyn = marclyn;`

she is made to yield a `cmode` value.

In all these cases, *marlyn* is a constant. Strictly speaking *marlyn* is either an **amode** constant, or a **bmode** constant, or a **cmode** constant. So, recalling the fact that *marlyn* is declared to be of united mode, we might term *marlyn* a "united constant". United constants will be of little (if any) use when declared in this way, but these identity-declarations can easily arise when matching an actual-parameter to its formal counterpart in a routine (as in 2.6.2.E8, for example).

### 1.6.1.2. Equivalence of unions

Let *nylram* be a ref *abcmode*, i.e. *nylram* yields the name of a union (*amode*, *bmode*, *cmode*). Although there is no such thing as an *abcmode* value, a ref *abcmode* is a well shaped internal object as are all names; it is simply a name referring to a union.

Consider the identity-declaration:

(E2) `ref abcmode marlyn = nylram;`

it elaborates into:

<figure><img src="image_64.png" /></figure>
A copy of the name yielded by *nylram*, which refers to an *abcmode*, is ascribed to the identifier *marlyn*. Now *marlyn* and *nylram* both yield names referring to the same union.

But what about the identity-declaration:

(???) ref abcmode marlyn = maralyn (???)

The actual-parameter refers to an *amode* value; the formal-parameter, however, requires a reference to a union. Although in this union there occurs an *amode*, this water is too wide. You can assign an *amode* value to a variable which is united from *amode*; you can never make a reference to such a union refer to a value which occurs in that union. Try drawing the picture, it cannot be done!

### 1.6.1.3. Local united generation

The happening:

(E3) ref abcmode marlyn = loc abcmode;

or:

(E3*) abcmode marlyn;

can be depicted as follows:

<figure><img src="image_65.png" /></figure>
You might ask what value is now generated on the stack, because there is no such a thing as an **abcmode** value. You have to ask your implementor. His answer will be something pretty close to "I reserve sufficient locations for an **amode**, or a **bmode**, or a **cmode** and, for use in conformity-clauses (see 1.6.2), I also reserve space to record which of these is actually in residence".

### 1.6.2. Assignations and conformity-clauses

To an **abcmode** variable you may assign either an **amode** or a **bmode** or a **cmode** value. For example:

(E4) $marlyn := marblyn$

elaborates into:

<figure><img src="image_66.png" /></figure>

After this assignation the name yielded by *marlyn* now refers to a *bmode* value. In order to enable you find out which is the mode in force in a union, we have the 'conformity-clause'.

An important application of unions will be found in routines. Suppose you want to switch in a routine depending upon the mode of an actual-parameter when you declared the formal-parameter to be the union of several modes; then you most likely will want to find out (inside the routine) the mode of
the parameter actually supplied, which you may achieve as follows:

(E5) case *marlyn* in
    (*amode*) : c do this c,
    (*bmode*) : c do that c,
    (*cmode*) : c do the other c

    *esac*

In many cases it will not suffice to find out the mode actually supplied, you may also want to know its value. Now you cannot assign:

`marblyn := marlyn`

not even when the modes conform. The proper tool in such cases is the conformity-clause again:

(E6) case *marlyn* in
    (*bmode* *bvalue*) : *marblyn* := *bvalue*

    out c *marlyn*'s mode was not *bmode*; some alternative action can be taken here c

    *esac*

Here, we have declared a *bmode* identifier *bvalue* to which, provided *marlyn* "conforms" to *bmode*, her *bmode* value can be ascribed. The assignation *marblyn* := *bvalue* is then quite straightforward:

<figure><img src="image_67.png" /></figure>
Contrariwise, if *marlyn* does not conform to **bmode**, no assignment takes place and, since no specific alternative modes have been mentioned (as they were in E5), the clause in the **out** part will be taken.

**Vertical readers**, please turn to 2.6.

## 1.7. Distinctive features

As we pointed out in 1.2.3, all modes in this language are derived from the primitive modes with the assistance of the symbols **ref**, **proc**, **struct**, "[" and "]", **union**, **long** and **short**. Until now we have not discussed **long** and **short**, and we have not discussed the identity-relation for **ref** modes (names); these are the subject matter of this section.

### 1.7.1. The **long** and **short** modes

Going down to the level of a concrete computer, the values of all primitive modes (1.2.3) will be mapped into bit-patterns. A **bool** will most likely be a single bit, a **char** may be stored in at least six bits (more likely seven or eight, i.e. a "byte"), an **int** may occupy an entire machineword (**a bits**, see 2.7.1), a **real** one or two machinewords.

On most modern computers you will find provision for (if not in the hardware, then in the standard software) multilength arithmetic. That is to say, apart from an **int** occupying a single machineword, we may also be enabled to add, subtract, multiply and divide integers occupying, say, two machinewords, and maybe even larger ones (occupying three or more machinewords). The same may apply to **reals** and also to the primitive modes **bits** and **bytes** (discussed in 2.7.1), and there may in addition be further versions of all these occupying half, or even a quarter, of a machineword.

To distinguish between the various sizes of such values we have the long-symbol "**long**" and the short-symbol "**short**".

Thus we may distinguish an infinity of different modes

For integers:

*   **int**, **long int**, **long long int**, **long long long int**, ---
*   **short int**, **short short int**, ---
for real numbers:

real , long real , long long real , long long long real , ---
short real , short short real , ---

and similarly for bits and bytes.

In a specific implementation, only a few of these will in fact be
distinguishable as values of different length. The effective number of longs or
shorts is not necessarily the same for int, real, bits and bytes. It may be
acquired from corresponding environment enquiries (see 6.7.1).

Modes of different **length** and **shorth** derived from the same primitive
mode are different modes and it is therefore quite proper to unite from
different **lengths** and **shorths** derived from the same (or different)
primitives:

mode integral = union ( short int , int , long int ) ;

mode number = union ( real , long real , long long real ) ;

1.7.2. Identity relations

As was pointed out in 1.2, a 'reference to MODE' value is also an internal
object in the computer, i.e. a ref will also be mapped into a certain bit-pattern
(the address of the value referred to). Consequently, names may also be
operated upon and, in particular, compared. To compare names of the same
mode we have the identity-relators :=: (or is) and :‡: (or isn't).

Consider the following picture:

<figure><img src="image_68.png" /></figure>
## 2. DECLARATIONS

### 2.1. Primitive declarations

#### 2.1.1. Primitives

In the previous chapter, we considered values of a hypothetical mode `amode`. In ALGOL 68 there is in principle an infinite number of possible modes which could be substituted for `amode`, and in the course of the present chapter we shall show you how to construct them all. They are, however, all derived from a small number of "primitive" modes (1.2.3). The primitives are as follows:

**int** The values of this mode are the integers within some finite range dependent upon the implementation (e.g. from $-2^{31}$ to $2^{31}-1$ for a 32 bit binary machine). See 6.2.1 for how to find the size of the range. Arithmetic performed upon `int` values will in general yield exact results, the same in every implementation.

**real** The values of this mode will in general be held as floating point numbers by the implementation. Thus the range of numbers that can be held is much greater than for `int`, but one pays for this by a restricted precision (again see 6.2.1 for details).

**bool** There are only two values of this mode, `true` and `false`.

**char** The values of mode `char` are characters – i.e. internal representations of certain graphic marks on external media. These graphic marks will include at least the letters `a` to `z`, the digits `0` to `9`, `"`, `+`, `-`, `(`, `)`, point, comma and space. Most implementations will add others to this list, and we shall assume, in our examples, that this has been done (and in particular we shall use `A` to `Z` quite freely).

**bits** The values of these modes are computer words, regarded as a collection of bits or of characters, see 2.7.1.

#### 2.1.2. Variable declarations

Whenever we wish to have, at our disposal, a variable value of some mode, we must declare it, and provide an identifier to yield its name (1.1:1):
(E1) real x; int i; bool p; char c;

A variable-declaration [R 4.4.1.e] consists of:

a) an 'actual-declarer' (real, int, etc.) which specifies the mode of the variable value created thereby. For every mode which can be constructed in the language, an actual-declarer can be written. For example, real, ref real, ref ref real, int, ref char, bool, etc. are all perfectly good actual-declarers, and the mode that each specifies is obvious.

b) an identifier (x, i, etc.) to which the name referring to the newly created variable is to be ascribed.

If we have to declare several variables of the same mode, we have three methods:

(E2) real x; real y; real z; int i; int j;

(E3) real x, real y, real z, int i, int j;

(E4) real x, y, z, int i, j;

E3 and E4 are 'collateral-declarations'. In fact they mean exactly the same thing, but the "contraction" E4 is more convenient to write. The difference between E2 (with ","s) and E3 (with ","s) is that the declarations take place serially in the first case and collaterally in the second. The difference between them is quite academic in the case of these simple primitives, but could be of crucial importance in more complex situations, such as we shall meet in 2.5. Declarations are always separated from each other, and from other clauses, by go-on-symbols (i.e. ","s), and for this purpose a collateral-declaration such as E4 counts as one declaration:

(E5) bool p, real x, y, z, int i, j; char c;

Now that we have declared these variables, we are free to use them:

(E6) x := 3.142;

y := x;

i := 3

### 2.1.3. Sample declarations

In the chapters that follow, we shall give many examples using identifiers such as x, y, i, j, etc. To save confusing you, we shall not declare them each time we use them, and so whenever you see such an example, please assume the declarations listed in Appendix 2 to have been already made. You have
already met most of them in Chapter 0 (where they were conspicuously
marked with a "D"), and the Report itself also uses most of them in the same
way [R 1.1.2].

Vertical readers, please turn to 3.1.

## 2.2. Identity declarations

Identifiers are declared in 'identifier-declarations' of which there are two
kinds - the variable-declaration, which has just been described (2.1.2), and
the identity-declaration, which follows.

### 2.2.1. Identity declarations

An identity-declaration serves to introduce a new identifier, to specify the
mode of the internal object (value) that is to be ascribed to it, and to fix that
value. Thereafter, until the end of the range (3.2.1) in which that identity-
declaration occurs all other occurrences of that identifier are deemed to yield
that same value (see 3.2.3 for the precise mechanism of this).

An identity-declaration [R 4.4.1.a] has two sides - its left hand side, or
'formal-parameter', and its right hand side, or 'actual-parameter'. Consider:

(E1) $real\ e\ =\ 2.718281828;$

An identity-declaration is constructed as follows:

Its LHS (the formal-parameter) (real *e* in the example) consists of:

a) a 'formal-declarer' (real) which simply specifies the mode of the
internal object. For every mode which can be constructed in the
language, a formal-declarer can be written. For example, real, ref real,
ref ref real, int, ref char, bool, etc. are all perfectly good formal-
declarers, and the mode that each specifies is obvious.

b) an identifier (*e*) to which the object is to be ascribed.

Its RHS (the actual-parameter) (2.718281828 in the example) consists of:
a unit whose context is strong, and which yields a value whose mode
(after coercion if necessary) is the same as that specified by the
formal-parameter. This value is now ascribed to the identifier, after
which the identifier will always yield that value.

The whole of Chapter 5 is devoted to describing what can and cannot
stand as a unit, and to explaining all about the strength of contexts and
coercion, so that it would be inappropriate here to do more than give a few examples that are particularly important. If you have already read 5.1.4.1, you will have noticed the similarity between the rule just given for an actual-parameter and that appropriate to the RHS of an assignation.

An identity-declaration is therefore a very simple concept, with a simple syntax and simple rules. Do not therefore be afraid when you come across a particular example which seems to go on for page after page. It is simply because a long and complicated formal-declarer has been used to specify a long and complicated mode, or because the unit on the RHS happens to be rather a long one. The effect is just the same. We associate together a particular mode and a particular identifier, and ascribe to that identifier a particular value of that mode.

Note, however, that once a value has been ascribed to the identifier, this value cannot be changed (it is a constant (see 1.2.2.1)), and the compiler should be able to take advantage of this. After E1:

$$ (E2) \quad x := e $$

should compile into exactly the same code as:

$$ (E3) \quad x := 2.718281828 $$

Things are slightly more complicated with examples like:

$$ (E4) \quad \texttt{real xy = x \times y} $$

Here, the value to be ascribed to `xy` is to be calculated (`x \times y`) at the time when this declaration is encountered during the elaboration of the program, and if it is encountered several times the values will presumably be different on each occasion. Nevertheless, although the compiler will now, presumably, have to reserve a word of store to hold this value, it should still be able to gain some benefit from knowing that it cannot change until the next time.

### 2.2.2. Another look at variable declarations

(E5) `real x;` or even `loc real x;`

We have already seen that `real` is an actual-declarer which creates a `real` variable, and that the name referring to this variable is ascribed to `x` (making `x` a ref real identifier). So it seems that we have two methods of creating a ref real identifier and ascribing a value (more specifically a name) to it. Let us therefore try to construct an identity-declaration to do precisely the same job as the variable-declaration E5. Presumably it will look something like this:
ref real x = "something"

In this example, "something" must obviously be a unit that yields a constant value (a name) of mode ref real, but it must also have the property that it reserves a space in the store where a real value may be put, and it is the name referring to this space that it must yield. If you search through Chapter 5 looking for such a unit, you will find that it is known as a 'generator' and is not described until 5.7.2. This is because the use of generators is rather specialised. There are two kinds of generator, and we recommend the loc one for the present purpose (as we have already explained in 1.2.2.3):

(E5*) ref real x = loc real;

loc real is the generator, and the mode it yields is ref real in spite of its appearance to the contrary. The loc signifies that the real value thus created is local to the current range, as will be explained in 3.2.2. real is an actual-declarer.

If you feel like trying a heap generator, then you should read 2.7.3 first.

Of course, we have already met this before in 1.2.2.3 – E5 means exactly the same as E5*. But please remember the distinction between formal-declarers (such as ref real in E5*), which merely specify modes, and actual-declarers (such as real in E5 and on the RHS of E5*), which, in addition, generate values of the mode specified. This distinction may not seem important just now, but you will forget it at you peril when you come to 2.5.2 and even in 2.2.3 it will be relevant.

### 2.2.3. Initialized variable declarations

We explained in 1.2.2.3 how you could write:

(E6) real ee := 2.718281828;

which has created a real variable and assigned an initial value to it all in one go. But beware! E6 (at least in this representation) looks deceptively like E1 – the difference is just one ":". We can subsequently assign a different value to ee (E6), but never to e (E1).

Now, if we have the collateral-declaration:

(E7) real x := 1.0, real y := 2.0;

we may apply our usual contraction to obtain:

(E8) real x := 1.0, y := 2.0;
Likewise, if we had had:

(E9) real x = 1.0, real y = 2.0;

we could have obtained:

(E10) real x = 1.0, y = 2.0;

which simply goes to show that formal-declarers (the reals in E9) may be
gathered together in just the same way as actual ones (the reals in E7). But:

(E11) real x = 1.0, real y := 2.0;

which is perfectly good collateral-declaration, creating a real object x and a
ref real object y, cannot be contracted to:

real x = 1.0, y := 2.0;

for here we would be gathering together one formal-declarer and one actual
one, and moreover it would be too confusing to have the one declarer real
being used to create objects of two different modes.

Vertical readers, please turn to 3.2.
## 2.3. Mode declarations

We introduced mode-declarations to you in 1.3.3.1; Consider:

(E1) `mode myproc = proc(real, int, ref char) bool;`

This is a 'mode-declaration'. On the LHS we have introduced the bold word (1.3.2) `myproc` as a 'mode-indication'. On the RHS we have an actual-declarer specifying the required mode. Henceforth, (or at least within this range) `myproc` and `proc(real, int, ref char) bool` may be used interchangeably. You may have declarations such as:

(E2) `myproc proc;`
`ref myproc refproc;`

and you may now embark upon the construction of even more elaborate modes such as:

(E3) `proc(myproc) void`

See 2.5.2.2 for mode-declarations of 'row of' modes where bounds must be specified.

Naturally, a mode-declaration may be combined with other declarations (whether they be other mode-declarations, or even identifier- (1.1.2), priority- (4.3.1) or operation- (4.3.2) -declarations) into a collateral-declaration:

(E4) `mode rl = real, mode it = int, mode bo = bool, real x;`

to which we may now apply our usual contraction, collecting together all the modes:

(E5) `mode rl = real, it = int, bo = bool, real x;`

Vertical readers, please turn to 3.3.
## 2.4. Declarations of structures

### 2.4.1. struct declarers

The concept of a "structure" was introduced in 1.4.0. Each structured value is of some mode, and for each such mode we can write a declarer (and up to this point, formal- and actual-declarers are still looking the same):

(E1) struct/real first, int second, ref char third)

This is the way you would write a struct declarer [R 4.6.1.d]; but should you wish to declaim it in public you would take a deep breath and say*:

"structured-with-(a-)real-field-first-(and-an-)integral-field-second-(and-a-)reference-to-character-field-third-mode"

This is the way in which the Report would specify this mode [R 1.2.1], but in this Introduction we shall stick to the corresponding declarers — they are much cleaner.

first, second, and third in E1 are 'field-selectors', not identifiers, and they are a part of the declarer, which identifiers could never be. Thus:

(E2) struct (real fourth, int fifth, ref char sixth)

specifies a different mode from that specified by E1. A value of one could not be assigned to a name referring to a value of the other.

The fields inside a structure can be of any mode whatsoever, including of course other structs:

(E3) struct (proc ( real, int, ref char) bool pr, struct (real first, int second, ref char third) group)

Where two adjacent fields are of the same mode, the usual contraction is possible, as in:

(E4) struct (real re, im)

The only limitation is that a struct cannot contain itself (2.4.3), although it can contain a reference to itself. To achieve this, however, we must use a mode-declaration (2.3):

(E5) mode sequence = struct (int object, ref sequence next);

Modes such as this are particularly useful in conjunction with heap generators

<footnote>* If some pedant should notice that even this verbosity is not the full story, let him please keep the secret to himself.</footnote>
(5.7.2.2), and for a substantial example of their use you are referred to 8.7.1.

### 2.4.2. struct declarations

Now we can use **struct** declarers in the formal-parameters of identity-declarations, or as the actual-declarers in variable-declarations:

(E6) struct (real x, int i) st = (3.14, 123);

in which a constant *st* is created, and

(E7) struct (real x, int i) ss;

in which a variable *ss* is created. *ss* can now be assigned to other variables of the same mode, or its individual fields may be accessed using their selectors:

(E8) x := x of ss

This subject will be treated more fully in 5.4.2.

### 2.4.3. Well-formed modes

The mode-declaration 2.4.1.E5 was circular. However, not all such circular mode-declarations are valid. There are two dangers to avoid:

a) we must avoid modes whose values would occupy an infinite amount of storage space (consider the problems of representing a **large** as specified by **mode large** = **struct** (int *large*, *large* **larger**); );

b) we must avoid modes which could be strongly coerced into themselves (how many times should you dereference the RHS of **ref itself** who = **loc itself**, given that **mode itself** = **ref itself**?).

Here is how to distinguish the sheep from the goats [R 7.4.1].

Start from the mode-indication on the LHS of the suspect declaration.

Now look through the RHS, marking, or "shielding", each **ref** or **proc** with the word "yin", and each **struct** and each set of parameters of a **proc** with the word "yang".

At each mode-indication you encounter, find the mode-declaration that it identifies (3.3.1), and continue there.

Eventually (because it is circular), you will get back to the mode-declaration which you started from.

So we have:

(E9) mode sequence = struct (int *object*, ref sequence *next*);
            yang          yin
and, in a more complicated case:

(E10)
mode a = struct (ref b f1, union (int, a) f2),
  yang yin
mode b = proc (int, int) a;
  yin yang

Now consider all routes from your starting mode-indication returning to the same point. Is each route properly shielded by passing through at least one "yin" and one "yang"? If not, the mode is not well formed and the mode-declaration is invalid. E9 passes the test. In E10, there are two routes from a back to a again. One passes by way of "yang-yin-yin-yang" but the other can only manage "yang". It can be shown that a missing "yin" will land you in danger (a) above, and a missing "yang" will put you in danger (b). Keep your yin and yang in the correct balance and you will attain harmony.

### 2.4.4. The mode compl

The mode compl (for complex) is not a primitive in the language, although you would not come to much harm if you were to regard it as such, since it is provided with a complete set of operators and other useful facilities (5.4.0 and 5.4.3). It is, in fact, a struct, being declared in the standard-prelude (1.1) [R 10.2.2.f] by:

(E11)
mode compl = struct (real re, im);

Vertical readers, please turn to 3.4.
## 2.5. Declarations of multiples

### 2.5.1. Row declarers

The concept of a "multiple value" was introduced in 1.5.1. Each multiple value is of some mode, and for each such mode we can write a declarer. Now, however, we are at the point where formal- and actual-declarers begin to look different. Here is a formal-declarer:

(E1) [,] ref real

which is pronounced:

‘row row row of reference to real’

This specifies the mode of a multiple value which needs three subscripts (because there are two ","s between the "[]" add the "]"), and whose elements are names of mode ref real.

Here is an example of a formal-declarer whose interest lies in its complexity, rather than in any use it might have:

(E2) [] struct (proc (int, ref [] real) [] real p,
         [] [] ref compl q)

The pronunciation of this one is left to the proverbial student as his pro-
verbial exercise. You have enough information to do it, but have you the
stamina? However, this example does show that we may have rows of structs
and of other rows, structs containing rows, and procs that use and yield
rowed modes. Observe the difference between [,] [] real ('row row of row
of real') and [,,] real ('row row row of real'). The first is a doubly subscripted
multiple each element of which is a singly subscripted one. The second is a
straightforward triply subscripted multiple value.

### 2.5.2. Row declarations

In a variable-declaration involving a 'row of' mode we encounter a problem
that did not arise before. A multiple value consists (1.5.1) of a descriptor and
a set of elements, and whenever we create such a value, not only must it be of
the required mode, but its descriptor must fit our requirements as well. It is
the responsibility of the actual-declarer to ensure that both these
requirements are met.
### 2.5.2.1. Fixed and flexible names

A multiple value is simply a row of elements together with a descriptor, and its mode is something like `[,] real`. Observe that the mode tells you the number of subscripts, but not the number of elements. So, you may ask, if I have a multiple value with 100 elements, may I supersede it with another one of 200 elements (but of the same mode, of course)?

The answer is that "it all depends". Superseding takes place during assignation (1.1.2.2), in which the value superseded is that referred to by the name on the LHS. It is the name which controls the location where the elements are kept, and so it is the name which determines whether the location is flexible enough to accommodate the greater number of elements. If the mode of the name is `ref flex [,] real`, well and good, but if its mode is only `ref [,] real` the assignation will not be allowed.

Thus we have the situation (which only arises with multiple values) that a value may be referred to by either a "flexible name" (with a `flex` after the `ref` in its mode) or a "fixed name" (without a `flex`). Nevertheless, the mode of the value itself is the same in either case. There is no such mode as `flex [,] real`.

Suppose that `rowvar` yields a flexible name of mode `ref flex [ ] real`. You will see presently that `rowvar` could have been declared as follows:

`flex [1:0] real rowvar := skip;`

where the `skip` is to signify that we do not at the moment have the slightest idea what size it is, or what are the values of its elements.

Here now is an identity-declaration:

(E3)  [ ] real xl = rowvar;

Since `xl` is not a name, no question of flexibility arises. `xl` now simply yields the multiple value obtained from `rowvar`, with whatever number of elements that had.

Here is another identity-declaration:

(E4)  ref flex [ ] real xlm = rowvar;

Now `xlm` yields the same flexible name as `rowvar`, and refers to the same location in store. The `flex` was necessary in order to match the mode of `rowvar`. If we have a fixed name `rowfix` of mode `ref [ ] real` declared by:

[1:10] real rowfix;

then the corresponding declarations are:

(E5)  [ ] real xf = rowfix;
(E6) ref [] real xfg = rowfix;

### 2.5.2.2. Actual 'row of' declarers

A 'ROWS of' variable-declaration contains, of course, an actual 'ROWS of' declarer. This has to reserve a substantial region of store, and so it must know how much store to reserve, and whether it is likely to be changed later (through being flexible). This information is provided by bounds in the actual-declarer:

(E7) [1:99] real xfgh;

(E8) flex [1:99] real xlmn;

Space for 99 reals is reserved, with the option of altering it later in the second case, and arrangements are made to release the space again when the current range is left.

Since an actual-declarer is actually going to reserve some actual store, of some actual size, it follows that the bounds must be actually present. If the upper-bound is less than the lower-bound, then the descriptor is "flat" and the number of elements in the multiple is taken as zero (the bounds [1:0] are frequently used when an initially empty multiple is to be created, as in 2.5.E11 below. If the lower-bound is 1, it may be omitted as in

(E7*) [99] real xfgh;

A bound can be any meek int unit, and you will see in Chapter 5 that this covers a large number of possibilities. All the bounds in the actual-declarer, together with the RHS if the declaration is initialized (2.2.3), are elaborated collaterally each time that the variable-declaration is encountered [R 4.4.2.b].

Also, since a variable-declaration creates a name whose mode has a ref in it (2.2.2) (even though this ref does not appear in the actual-declarer), it follows that an actual-declarer may start with a flex (as in E8) if the name created is to be a flexible name. This may seem more natural if E8 is written in its alternative form:

(E8*) loc flex [1:99] real xlmn;

Next you might like to reflect upon the fact that the RHS of a mode-declaration (2.3) is an actual-declarer, so that not only may a mode-indication be made to specify a mode, but it then also specifies bounds and flex, where relevant, as well. A splendid example of this is the mode string declared in
2.5.3. If such a mode-indication now appears as or in a formal-declarer, no harm is done, the actual-bounds and any **flex** associated with it simply being ignored.

However, if the bounds of a mode-declaration require elaboration, as *n* in:

(E9) mode *a* = [1 : *n*] real;

then they are not elaborated at the time this mode-declaration is encountered. Instead, it is the value of *n* in force at the time *a* is applied that matters:

(E10)
*   $n := 1;$
*   $a \dot{a};$ \quad $\ddot{\}$ i.e. [1 : 1] real $a;$ $\ddot{\}$
*   $n := 2;$
*   $a \dot{b};$ \quad $\ddot{\}$ i.e. [1 : 2] real $b;$ $\ddot{\}$

### 2.5.2.3. Summary

Let us now summarize the differences between actual- and formal-declarers: A 'row of' actual-declarer must have bounds and may start with **flex**:

[1 : 99] real flex [1 : 99] real

moreover, if an actual-declarer specifies a **struct** mode, then its fields are also actual-declarers:

struct ([1 : 99] real *a*, struct (int *c*, flex [1 : 99] real *d*) *b*)

A formal-declarer never has any bounds, and never starts with a **flex**:

[ ] real
struct ( [ ] real *a*, struct (int *c*, [ ] real *d*) *b*)

However, if it starts with a **ref**, or has a **ref** anywhere within it, then **flex** may occur in parts of the declarer controlled by that **ref**:

ref [ ] real ref flex [ ] real
ref struct ( [ ] real *a*, struct (int *c*, flex [ ] real *d*) *b*)
ref [ ] flex [ ] real
ref ref flex [ ] real

Moreover, certain declarers are always constructed like formal ones, even if they occur as or inside actual ones. These are declarers beginning with **ref**, **proc** or **union**, so that the following are all correctly formed actual-declarers:

ref [ ] real [1 : 99] ref flex [ ] real
struct ([1:99] real a, ref struct (int c, flex [] real d) b)

proc ([] real) [] real

union ([] real, [] int)

### 2.5.3. The mode string

The mode **string** is not a primitive in the language, although you would not come to much harm if you were to regard it as such, since it is provided with a complete set of operators and other useful facilities (5.5.1.1, 5.7.0.2, 6.1). It is, in fact, a [] **char**, being defined in the standard-prelude (1.1) [R 10.2.2.i] by:

(E11) mode string = flex [1:0] char;

An interesting consequence of this is that if we declare:

(E12) string t;

we have not created an object with an undefined value as we would have done in:

real x;

Instead, *t* has been made to refer to an empty **string**, which is a very definite (and useful) entity, and the only thing undefined about it is the value of the elements which it hasn't got.

Because **flex** is only meaningful after a **ref**, the mode **string** is the same as the mode [] **char**, but the mode **ref string** is equivalent to **ref flex [] char**.

**Vertical readers**, please turn to 3.5.
## 2.6. Union declarations

### 2.6.1. union declarers

We introduced you to unions in 1.6.1. Although we cannot create values of united modes, we can talk about such modes, and to do this we need declarers:

(E1) union ( [ ] real, [ ] int)

Note how the inside of a union is always formal (2.5.2.3), so that there is no difference in appearance between formal and actual union declarers [R 4.6.1.s].

You will remember that (1.6.1) the order in which the modes are specified inside a union is quite immaterial [R 4.6.1.s, R 7.3.1.k], so that:

(E2) union ( [ ] int, [ ] real)

specifies exactly the same mode as that specified by E1. Moreover:

(E3) union (int, string, union (real, union ( [ ] char, int)))

could equally well (and with less ink) have been:

(E4) union (int, real, [ ] char)

However:

union (int, ref int)

is not allowed because, if this mode were required (a posteriori) in a firm context (e.g. as the operand in a formula), and a ref int were available (a priori), we should not know whether to dereference it and then unite it (5.6.0), or whether to unite it straight away. It is therefore forbidden for a component mode of a union to be firmly coercible to one of the other component modes or to the union of those others [R 4.7.1.f]. Thus:

union (ref union (int, real), int, real)

would not be correct either, because ref union (int, real) can be firmly coerced to union (int, real).

### 2.6.2. union declarations

Now we can use union declarers in the formal-parameters of identity-declarations, or as the actual-declarers in variable-declarations:
(E5) union (real, int) ir = (p | 2 | 3.14);

in which a constant *ir* is created (either **int** or **real** depending on the yield of *p*), and

(E6) union (real, int) ri;

in which a variable *ri* is created, to which either a **real** or an **int** may subsequently be assigned (5.6.0). At the moment, it is not defined whether *ri* refers to a **real** or an **int**, but it will certainly be one of them [R 4.6.2.a].

Since there is no such thing as a value of a united mode, there are some declarations which, whilst being legal, are not at all useful:

(E7) union (bool, real) br = 3.142;

*br* will now, in fact, always yield a **real** value, but wherever it is used allowance for both possibilities will nevertheless be made (and, for example, *x* := *br* will not be allowed). This declaration could, however, very reasonably arise when matching the actual-parameter of a call to the formal-parameter of a routine-text (1.2.3.2.1):

(E8) proc pbr = (union (bool, real) br): XXXXX;
pbr (3.142)

Here, *pbr* yields a routine which is prepared to accept either a **bool** or a **real** as its actual-parameter (and occurrences of *br* within XXXXX will be treated accordingly).

**Vertical readers**, please turn to 3.6.
## 2.7 bits, bytes, longs and shorts

### 2.7.1. bits and bytes

bits and bytes [R 10.2.2.g,h] are two primitive modes which are intended to give you access to the actual words in your computer, so that you may achieve greater efficiency. bits is similar to [] `bool` and bytes to [] `char` (or string), except that the number of `bools` or `chars` respectively is limited to exactly that number which can be fitted into one computer word. Thus individual bits or bytes values can be passed around inside your program with great efficiency, at the expense of some additional effort (by widening (5.7.0.2) or the procedures `bitspack` and `bytespack` (6.2.2) and the operator `elem` (6.1.2)) whenever you want to get at the individual `bools` or `chars` within them. Environment enquiries are provided (6.2.1) to tell you how much you can get into a single bits or bytes in your implementation.

bits and bytes are, of course, easily declared:

(E1) bits *bits*; bytes *bytes*;

Note that [] `bits` and [] `bytes` may be declared and `bits` and `bytes` may appear inside `struct`, `union` and `proc` modes.

### 2.7.2. long and short modes

Double, triple, etc. length working is used in computers in order to obtain greater accuracy, or to distinguish between a greater number of possible values of some mode, or to pack more information into one value. The ALGOL 68 modes where this facility would be useful are:

* `int`, `real`, `compl`, `bits` and `bytes`

Indeed, it is possible to prefix all of these modes by `long` in order to obtain new modes of approximately double the precision, by `long long` for triple precision, and so on. A given implementation does not have to carry this on indefinitely, however. After some number of `longs` (perhaps only one) it will treat values of `longer` modes as being of the same precision. Various environment enquiries are provided to tell you how many `longs` are effective, and how precise they are (6.7.1), and a full set of operators (6.7.3) and procedures (6.7.2) is provided for them.

`long` modes are, of course, easily declared:

(E2) long real *reaeal*; long long int *iiiiiint*; proc (long int, int) long long int *power*;
In the same manner, these modes may be prefixed by "short" in order to
take advantage of any facilities in the hardware for manipulating half words
or individual bytes. Again, after some number of shorts (perhaps none at all)
further shorts will make no further difference to the precision. Appropriate
environment enquiries, operators and procedures are provided as before.

(E3) short real *rel*; short short int *it*;
proc (short int, int) short short int *root*;

### 2.7.3. heap declarations

Just as:

(E4) real *x*;

which may also be written as:

(E4*) loc real *x*;

means the same thing (2.2.2) as:

(E5) ref real *x* = loc real;

so:

(E6) heap real *x*;

means the same as:

(E7) ref real *x* = heap real;

in which the **heap real** is a **heap generator**. The effect of E6 is to reserve a
space in the store for the variable *x* which will not disappear when the current
range is left. (It will not, of course, then be accessible via the identifier *x*, but
its name may in the meantime have been assigned to a **ref real** variable with a
larger scope).

This and other uses of **heap generators** will be described more fully in
5.7.2.2.

**Vertical readers**, please turn to 3.7.
# 3. CLAUSES

## 3.1 Serial clauses

A particular-program (1.1) [R 10.1.1.g] consists of an ENCLOSED-clause (3.2.4), which is usually a 'serial-clause' enclosed by embedding between *begin* and *end* (or, if you prefer, between "(" and ")", which can be used as alternatives wherever *begin* and *end* may occur).

The bricks out of which a serial-clause is constructed are called 'declarations', 'statements' and 'expressions'. Declarations we have already met (1.1.3 and 2). 'Statements' and 'expressions' [R 3.0.1.b, c] are alternative names for 'void-units' and 'MODE-units' respectively, and units in general will be discussed in Chapter 5. In the meantime, it will suffice to say that:

$$x := a+b$$

is a statement (usually) and:

$$a+b$$

is an expression (likewise).

We shall also need 'go-on-symbols' (better known as semicolons) which constitute the mortar which bind the bricks together, and 'labels' which enable us to find our way around.

### 3.1.1. The declarations

The building rules are really quite simple [R 3.2.1]. The foundations, which come first, consist of declarations (as many as you like) with mortar in between:

(E1) **begin**

¢ the **begin** is not part of the serial clause proper; it is
the earth in which the foundations are embedded ¢
real *a*;
int *i*;
char *c*, *d*, *e*;

The last one is a collateral-declaration (see 1.1.3) meaning the same as:

(E2) **char c, char d, char e;**

however, it all counts as one brick for our present purpose.
Statements are also allowed within the foundations (but not labels). This is particularly useful when you are declaring multiple values (as described in 2.5.2) in which the bounds are first to be calculated:

(E3) begin

    int i;
    read (i);      ¢ (7.1.2) ¢
    [1 : i] real x1; ¢ declares a multiple with bounds 1 to i ¢

Note that it is perfectly possible for there to be no foundations at all, the building starting straight away with the walls. This would be rather unusual for the serial-clause which constituted the body of a particular-program, but there are plenty of other places where such serial-clauses could occur.

### 3.1.2. The statements

The walls come next, and these too may be entirely absent. They consist of statements and semicolons, with labels attached where required (a label always comes before a statement (or before an expression, or even before the whole particular-program) and consists of an identifier (1.1.2) followed by a colon).

(E4) begin

    int i; real x, y, z;
    comment those were the foundations: now for the walls comment
    z := 1 - 3 x sqrt (small real); ¢ for small real see 6.2.1 ¢

    labl: read (i);
    x := i;

    lobl:
    lobl: y := i/x↑2;
          x := (2 x x + y)/3;
          if y/x < z then go to lobl fi;
          print (x); ¢ (7.1.1) ¢
          go to labl;

This will compute and print the cube roots of the (nonzero) integers read in. The conditional statement (if ...... fi) does what you would expect it to do (see 3.2.4.2 for details).

We now observe (as you have doubtless guessed already) that when a statement is followed by a “;” the completion of the elaboration of that statement is followed by the initiation of the elaboration of the following statement. Only when we come to a go to statement (consisting of go to
followed by a label-identifier, or alternatively of just the label-identifier) is
this sequence broken. Note that several labels can precede one statement (as
*lobl*: and *lubl*: in E4).

### 3.1.3. The yield

Finally, we come to the roof. This consists of just one statement (void-unit) or one expression (MODE-unit) (and there may be some labels before it).

(E5) begin
    int *i*; *read* (*i*); *real* *x*, *y*, *z*;
    ¢ those were the foundations ¢
    *z* := 1 - 3 × sqrt (*small real*); *x* := *i*;
    *lobl*: *y* := *i*/*x*↑2; *x* := (2 × *x* + *y*)/3;
    if *y*/*x* < *z* then go to *lobl* fi;
    ¢ those were the walls ¢
    *print* (*x*)
end
¢ the end is part of the embedding, too ¢

In this case the roof (*print* (*x*)]) was a statement — it was, in fact, just the last statement of the clause, and if there had been any more following it would have been quite content to be part of the walls.

Note that, in accordance with the best building practice, there is no mortar underneath the foundations, and there is none on top of the roof. Also, there is exactly one “;” between each brick. Contrast this with ALGOL 60 where extra “;”s mostly did no harm.

Now, if the roof is an expression, then it must yield a value. What happens to this value?

(E6)
    *a* := *b* + (*real* *x*, *y*, *z*; *z* := 1 - 3 × sqrt (*small real*); *x* := *i*;
    *lobl*: *y* := *i*/*x*↑2; *x* := (2 × *x* + *y*)/3;
    if *y*/*x* < *z* then go to *lobl* fi;
    *x*)

Here the piece between the “(” and the “)” is indeed a serial-clause and it occurs in a place where it is expected to yield a value (it is in fact a real-serial-clause). *x* is its roof and is an expression which (after a little dereferencing — see 1.1.6) yields a real value. This value now becomes the value of the serial-clause as a whole, and in due course it gets added to *b*, and the result is put into *a*.
### 3.1.4. Completers

We will now consider buildings with several roofs. Suppose, in the example E6, we only wanted the cube root of *i* if *i* was positive and the cube root was less than 10.0 (actually, it was rather a poor way of finding cube roots for largish numbers anyway). In the other cases, we wanted to print a message and to yield the result 10.0 regardless. Then we could build a house like this:

<figure><img src="image_69.png" /></figure>

We have to make it an Australian house, so that you can read the program from the top downwards. We also included one or two short cuts in the program, which you might be able to follow.

Observe that the foundations are common to both roofs. The complete statement containing the two-roofed serial-clause (and without the short cuts) will now look like this:

(E7)

a := b + (real x, y, z; z := 1 - 3 * sqrt(small real); x := i;
    if x <= 0 then go to libl fi;

lobl: y := i/x↑2; x := (2 * x + y)/3;
    if y/x < z then go to lobl fi;
    if x >= 10.0 then go to libl fi;
    x exit

libl: print ("out of range");
    10.0)

`exit` means that we have come to the first roof, and if this point is reached during the elaboration, then *x* is the value of the serial-clause. Otherwise (there being no more `exits` in this particular clause) 10.0 is the roof and provides the value. Inevitably, the `exit` must by followed by a label (for how else could the following statement be reached), and so the `exit` with its label attached constitute what is known as a 'completer' and the process of leaving a serial-clause through the roof (i.e. via either the *x* or the 10.0 in the E7
example) is known as "completing". Contrariwise, if you jump out of the middle of a serial-clause by means of a **go to** (out of the window perhaps) then that is to "terminate" it, and in this case no value is yielded. The mode of the value yielded on completing may be coerced and balanced (5.2.0.1) according to the context in which the serial-clause as a whole appears.

You can try imagining how E7 could have been written without the **exit** facility. It would have been necessary to re-arrange it so that the *x* to be yielded came right at the end. After *libl*, it would have been necessary to assign 10.0 to *x*, and then to **go to** another label just before the final *x*.

Note that, syntactically, a completer is a special type of mortar, so one does not expect to see any ";"s either before or after it. It might be tempting to regard it as a statement meaning "and now **go to** the end of the clause" but this would be dangerous since you must be quite sure first that you know which clause it will go to the end of.

### 3.1.5. Delimiters

In all the examples given above, the serial-clause itself was the part between the **begin** and the **end** (or "(" and ")"). However, serial-clauses can occur in a variety of contexts, and the complete list of delimiter pairs applicable is as follows:

<table><tr><td>between</td><td>begin</td><td>and</td><td>end</td><td>(in particular-programs or closed-clauses)</td></tr><tr><td></td><td>(</td><td>and</td><td>)</td><td>"</td></tr><tr><td></td><td>*if</td><td>and</td><td>then</td><td>(in conditional-clauses)</td></tr><tr><td></td><td>then</td><td>and</td><td>fi</td><td>"</td></tr><tr><td></td><td></td><td></td><td>else</td><td>"</td></tr><tr><td></td><td></td><td></td><td>elif</td><td>"</td></tr><tr><td></td><td>*elif</td><td>and</td><td>then</td><td>"</td></tr><tr><td></td><td>else</td><td>and</td><td>fi</td><td>"</td></tr><tr><td></td><td>*case</td><td>and</td><td>in</td><td>(in case- and conformity-clauses)</td></tr><tr><td></td><td>*ouse</td><td>and</td><td>in</td><td>"</td></tr><tr><td></td><td>out</td><td>and</td><td>esac</td><td>"</td></tr><tr><td></td><td>*while</td><td>and</td><td>do</td><td>(in loop-clauses)</td></tr><tr><td></td><td>do</td><td>and</td><td>od</td><td>"</td></tr></table>

<footnote>* Strictly, the clause between these delimiters is an enquiry-clause rather than a serial-clause – see 3.2.4.2.</footnote>
Closed- conditional- and case-clauses will be discussed in 3.2 and
conformity-clauses in 3.6.

Vertical readers, please turn to 4.1.
## 3.2 Closed clauses

### 3.2.1. Ranges and reaches

A 'range' [R 3.0.1.f] is a piece of source text which constitutes a serial-clause (or one which constitutes a routine-text (see 4.2.2.1) or certain portions of choice-clauses and loop-clauses (3.2.4, 3.5.2)). A range can "contain" further ranges within itself, and so on recursively. Here is a (not very sensible) particular-program, with all its ranges marked and numbered:

<figure><img src="image_70.png" /></figure>

A "reach" [R 3.0.2] is a range, with the exclusion of all the ranges
contained within it. Thus Re1 in the above example is a reach.

Note how the ranges in E1 are mostly serial-clauses contained between the delimiters listed in 3.1.5.

### 3.2.2. Scopes of names

Consider the declaration real *x* at the head of Ra2, which could also have been written as:

#### (E2) loc real *x*

When this is reached during elaboration of the program (i.e. just after the beginning of Ra2), a name is created (a location in the store is reserved) and is ascribed to the identifier *x* [R 4.4.2.b]. The loc in E2 means that the "scope" of this name is local, i.e. restricted to the lifetime of the range Ra2 (in whose declarations it occurs). Therefore, as soon as we cease elaborating statements within Ra2 (when we reach the delimiter end which terminates it in this instance), the name (to all intents and purposes) ceases to exist (the location in store is relinquished).

Thus, anything that you declare at the head of a range is only available to you inside that range (this is of course exactly the same as in ALGOL 60, except that there they are termed "blocks" instead of "ranges").

In an assignation (5.1.4.1) the scope of the RHS must be at least as old as that of the LHS, for otherwise the value referred to by the LHS would be undefined in some reach:

#### (E3) begin ref real *xx*; real *y*;

begin real *x*;

read (*x*); ₶ reads a real value (2.0, perhaps) ₶

*y* := *x*; ₶ this is all right because the real value is being as-
signed, and its scope is not limited ₶

*xx* := *x* ₶ this one is going to cause trouble ₶

end;

print(*y*); ₶ no complaints ₶

*y* := *xx*;

print(*y*) ₶ now what? ₶

end

In this example, the name *x* is newer in scope than the names *xx* and *y* (newer in the sense that it was created later than them and will disappear sooner). Thus the assignation *xx* := *x*, in which the name *x* was supposed to be assigned, was illegal.
### 3.2.3. Identification

Identifiers may occur in declarations -- these are called "defining-identifiers". In all other places (in assignations to take the most obvious example) they are "applied-identifiers". Consider the range Ra5 in E1. The identifier *p* is defined in:

(E4) $\mathbf{bool} \mathbf{p}$

and is applied in:

(E5) $p := \mathbf{true}$ and in $q := p$

Now it is up to the compiler to correlate each applied-identifier with a defining one, and when this has been done the former is said to "identify" or to be "within the reach of" the latter. The two occurrences of *p* in E5 thus identify the *p* in E4 (or E5 is within the reach of E4), still in the context of the range Ra5, of course, and this means that all these *ps* yield the same name (they get hold of the same location in the store) and they are all of the same mode (**ref bool** in this case).

Now, what about the identifier *i*, which has defining occurrences at the head of Ra1, Ra2 and Ra3 in E1, and applied occurrences (notably as *print(i)*) all over the place? The rule is quite straightforward [R 7.2]:

Start at the applied occurrence in question (call it "A")

Look for a defining occurrence in the same reach as A (call it "B")

If none is found,

→ then look for a defining occurrence in the reach which is immediately outside the range which contains the reach which you have just been looking at (call it "B")

If none is found,

A then identifies B.

Thus the "reach" of a particular defining-identifier is the range in which it is declared with the exclusion of all inner ranges within which it is re-declared. Note that, in some other languages, the term "scope" is used with this static meaning. In ALGOL 68, however, "scope" has another, dynamic meaning (3.2.2).

The arrows on the right hand side of example E1 show how all the applied occurrences of *i* are identified, and if you follow through the elaboration of this particular-program, you will find that what it prints out is:

1 T T 3 1 4 1 1 T T 3 1 4 1 1 T ...
where T is printed for the value true (see 7.1.1).

Note that, each time a new defining occurrence of *i* is encountered, then, until further notice, a new name is ascribed to *i*. This certainly does not mean that the old name yielded by *i* ceases to exist. It simply goes underground, and cannot be accessed (at least not via *i*) until after the end of the range in which *i* was redefined. It can, of course, be accessed if the programmer has made provision for some other object to yield or to refer to it.

Labels are identified just like any other identifiers, being defined as in:

labl:

and applied as in:

go to labl

This means that the go to lobl at the end of Ra5 can be used to jump out of Ra5 (which is then terminated — 3.1.4) into Ra2, which contains it; but it would be quite impossible to jump into Ra2 at lobl: from anywhere in the 'reach Re1. The identification just would not work. Thus, a range can only be entered via its declarations (which is just as well, if you think about it).

Finally, as you might expect, each applied-identifier must identify one, and only one, defining-identifier [R 7.2.1]. Thus all variables which you use must be declared (as in ALGOL 60, but not as in FORTRAN) and any given identifier may only be declared once within a reach. However, an applied-identifier need not necessarily come after its defining-identifier:

(E6) begin

proc a = real: b := c;

real b := 1, c := 2;

x := a

end

is perfectly legitimate (see 4.2.2.1 for further details of routine-texts, of which real: b := c is one). On the other hand:

(E7) begin

real b;

b := c;

real c;

c := b

end

is syntactically correct, and the identification of *c* works, but the assignation *b* := *c* will not work because no name has been ascribed to *c* at this point of
the elaboration (indeed, no such name has even been generated).

For the identification of modes see 3.3.1, and for operators see 4.3.3.

### 3.2.4. ENCLOSED clauses

An ENCLOSED-clause is either:

* a closed-clause (3.2.4.1)

* a collateral-clause (3.7.1)

* a parallel-clause (3.7.2)

* a structure-display (3.4)

* a row-display (3.5.1)

* a conditional-clause (3.2.4.2)

* a case-clause (3.2.4.3)

* a conformity-clause (3.6)

or a loop-clause (3.5.2)

<figure><img src="image_71.png" /></figure>

these 3 being known collectively as choice-clauses

ENCLOSED-clauses occur primarily in primaries (5.1.0.1). This means, inter alia, that they can stand as statements or as expressions (yielding respectively either void or some mode).

#### 3.2.4.1. Closed clauses

A closed-clause is a serial-clause enclosed between begin and end, or between "(" and ")" [R 3.1]. There are two chief reasons for using them. The first is to create some variables (strictly names) which are to be local to some range:

(E8)
begin
    real pie;
    begin
        real w := 0, int i := 1; real z = sqrt (small real/2);
        loop: w := w + 2/(i × (i + 2));
            i := i + 4;
            if 1/i > z then go to loop fi;
            pie := 4 × w
        end;
        print(pie)
    end
end

Here, the closed-clause was a statement, and it was created because w, i, z and
loop were not needed outside it. Here is a similar example in which the closed-clause is an expression:

(E9)

begin
    print (4 x ( real w := 0, int i := 1; real z = sqrt (small real/2);
        loop: w := w + 2/(i x (i + 2)); i := i + 4;
            if 1/i > z then loop fi;
            w ))
end

Indeed, 99% of an entire particular-program could be contained within one such expression. Note here the alternative form of the **go to** statement in which the **"go to"** is omitted.

The second reason why closed-clauses are used is to alter the priority of operators in formulas (5.1.3):

(E10)

`y := x * (a+b)`

In these cases, the serial-clause inside the closed-clause often contains just one unit (the building is nothing but a roof, using the metaphor of 3.1).

3.2.4.2. Conditional clauses

<figure><img src="image_72.png" /></figure>

An enquiry-clause is built like a serial-clause (3.1), except that it may contain no labels (apart from ones nested inside some ENCLOSED-clause within the enquiry) and hence no completers. The range that commences with its declarations extends right to the end of the conditional-clause (Ra1 above) and the two serial-clauses are also ranges (Ra2 and Ra3). Each of them can contain declarations, statements, other ENCLOSED-clauses and all the rest of the paraphernalia, or it can be as simple as a single unit:

(E11)

`if p then r else s fi`

where p would have to be a bool (or a proc bool), and r and s might be labels,
or they might be **procs**. Either way, *r* and *s* would be statements and therefore the whole conditional-clause would be a statement, and would yield no value.

In order to save ink, there are alternative representations that may be used for **if**, **then**, **else** and **fi**:

$(p|r|s)$

It is quite in order to omit the **else** and its associated clause:

$(p|r)$

If *p* is **true** the statement *r* is elaborated. Otherwise no statement is elaborated at all. However, this is not a sensible thing to do if the conditional-clause is expected to yield a value, for then the value yielded if *p* were **false** would be undefined.

$x := (i < j | a+b | a-b)$

That was a slightly more ambitious example. *i*<*j* is a formula yielding a **bool** value (5.1.3 and 6.1.2). The conditional-clause as a whole is required to yield **real** (in order that it may be assigned to *x*). Both *a+b* and *a-b* are formulas yielding **real**, and so all is well. As a matter of fact, it would have been sufficient for them to have been coercible to **real**, and a phenomenon known as “balancing” could have been invoked to aid the process. However, we shall leave discussion of this (and indeed of the coercion of all ENCLOSED-clauses) to 5.2.0.1.

<figure><img src="image_73.png" /></figure>
This is a piece of syntactic sugar to save you from writing (or forgetting to write) too many fis. It has an alternative representation:

(E12) $(p|r|:q|s|t)$

meaning:

(E13) if p then r else if q then s else t fi fi

### 3.2.4.3. Case clauses

<figure><img src="image_74.png" /></figure>

Some number, say $n$, of units are separated by “,”s. If the value of $i$ is such that

$$i \le 0 \text{ or } i > n$$

then the **out** clause is elaborated. Otherwise the $i$th unit is elaborated. If the case-clause as a whole is required to yield a value, then each unit must be capable of yielding a value of the required mode (but all legitimate coercions and balancings may be applied to this end (see 5.2.0.1)).

It is quite in order to omit the **out** and its associated serial-clause. If the clause as a whole is a statement, this means that no action is taken. If it is an expression, however, the value yielded is undefined:

(E14) begin int days, month, year;
days := case month in
    31, (year mod 4 = 0 & year mod 100 ≠ 0 v year mod
        400 = 0 | 29 | 28),
    31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31 desac
end
As usual, there are alternative representations for case, in, out and *esac*:

(E15) `print((i|"SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY"|"NODAY"))`

Corresponding to *elif* in conditional-clauses, there is *ouse* in case-clauses:

<figure><img src="image_75.png" /></figure>

If you think it confusing that “/”, “)”. “|” and “|:” should be able to represent so many things, please accept our assurance that no syntactic ambiguity arises. They are quick and easy to write, although it might be kinder to use the longer versions in algorithms intended for publication.

Vertical readers, please turn to 4.2.
### 3.3. Bold words

Certain bold words have fixed meanings in this language (e.g. real, begin, if – see Appendix 1 for the full list). All other bold words may be used for mode-indications and for operators. They are declared to yield modes or routines by means of mode-declarations (2.3) and operation-declarations (4.3.2). These declarations are valid for some range, and so the question of identification arises.

#### 3.3.1. Identification of mode-indications

The identification of identifiers was described in 3.2.3. The purpose and method of identification of mode-indications are exactly the same [R 7.2]. Consider the identification of r in:

<figure><img src="image_76.png" /></figure>

An explanation of the identification of operators will be postponed until 4.3.3.

Vertical readers, please turn to 4.3.
### 3.4. Structure displays

Structure denotations as such do not exist in the language. However, the required effect can be obtained by means of a particular form of ENCLOSED-clause known as a 'structure-display'. These can stand in any strong position where a primary yielding a structure would be allowed (because the position is strong, it follows that the exact mode of the structure-display is always known). Thus, given the declarations involving the mode vec in Appendix 2, and the declaration:

(E1) $\quad$ vec $v1$, $v2$, $v3$,

we can write:

(E2) $\quad$ $v1 := (1, 1, 1)$

but not:

(???)$\quad$ $v1 := v1 * (1, 1, 1)$

where the context would be firm (see 5.1.0 and 5.1.3).

A structure-display, then, is enclosed between “(” and “)” (or between **begin** and **end**) and contains one strong unit (5.1) for each field (of which there must be at least two) [R 3.3.1.e, h]. Because each field position is strong, widening is permitted (as indeed happened in the case of the (1, 1, 1) in the E2 example above). Because a field position is also a unit, structure-displays are considerably more than a substitute for structure denotations, e.g.:

(E3) $\quad$ $v1 := (x + 2, 3.4, i-3)$

Note that the various fields are elaborated collaterally (1.1.2.2).

**Vertical readers**, please turn to 5.4.
### 3.5. Row displays and loops

#### 3.5.1. Row displays

Multiple denotations as such do not exist in the language (except for the special case of **string** (5.5.1.1)). However, as in the case of structures (3.4), the required effect can be obtained by means of a particular form of **ENCLOSED-clause** known as a 'row-display'. These can stand in any strong position where a primary yielding a multiple would be allowed (because the position is strong, it follows that the exact mode of the structure-display is always known). Thus:

$$ (E1) \quad x1 := (1, 2, 3, 4); $$

$$ (E2) \quad y1 := (x, y, axb+1) $$

but not:

$$ (???) \quad xl := y1 + (1, 2, 3, 4, 5) $$

A row-display, then, is enclosed between "(" and ")" (or between **begin** and **end**) and contains one strong unit (5.1) for each of its elements (of which there must be at least two) [R 3.3.1.d, i].

Because each element is strong, widening is permitted:

$$ (E3) \quad x1 := (1, 2, 3, 4, 5) $$

Note that the various elements are elaborated collaterally (1.1.2.2).

A row-display yields, of course, a multiple value, whose elements are yielded by its units [R 3.3.2.b]. The lower-bound of this multiple is always 1, and the upper-bound is the number of units in the row-display. Thus

$$ (1, 2, 3, 4, 5) $$

has bounds $[1:5]$, and:

$$ ((1, 2, 3), (4, 5, 6)) $$

has bounds $[1:2, 1:3]$. Note how the row-display here contains as many row-displays as there are rows, each of which contains as many elements as there are columns.

A special kind of row-display, known as a 'vacuum', has no units at all and yields a multiple of appropriate mode with bounds $[1:0], [1:0, 1:0]$, etc.:

$$ (E4) \quad al := ( ) $$
### 3.5.2. Loop clauses

<figure><img src="image_77.png" /></figure>

For example:

(E5) **for** *i* from *k*−2 by 1 to *m* while real *lim* = max real/a; *x* < *lim* 
**do** *x* := *x* + *a*↑*i*/*i* **od**

This sums a certain series from *k*−2 to *m*, or until *x* is getting too large, whichever happens first.

Now a loop-clause consists of various parts labelled as I through S above. S is the serial-clause which is to be repeated. In E5 it was just one unit, but it will usually contain a substantial amount of program within itself:

(E6) **for** *i* from *j* by *k* to *l* while *p*
**do**
*x* := *x* + *x*1 [*i*];
*p* := *x* < max real/2
**od**

From inside S you may access I and you may do things which will alter the
yield of P, but you may not alter I because its mode is **int** and not **ref int** (this
means that the compiler is at liberty to treat I specially, perhaps keeping it in
some fast access register). You can do what you like to J, K and L, but it will
make no difference to the number of times the loop is obeyed, which is
determined once and for all (effects of P apart) at the beginning. The loop is
obeyed until I>L (or < if K is negative). I.e. the number of times obeyed is
$$
\text{entier} - \left( \frac{L-J}{K} + 1 \right)
$$

or zero if this is negative. The loop will be obeyed zero times if P yields **false** upon entry.
More precisely, the interpretation of a loop-clause is illustrated by the following piece of program, which is entirely equivalent to E6:

(E7) **begin**
    **int** *from* := *j*, **int** *by* = *k*, **to** = *l*;
    *¢* *j*, *k* and *l* are elaborated (collaterally) and their values are
    remembered. The counting is going to be done in *from* *¢*
    *m*: **if**
        *by* > 0 **^** *from* ≤ *to* ∨ *by* < 0 **^** *from* ≥ *to* ∨ *by* = 0
    *¢* i.e. **if** the count is not yet exhausted *¢*
    **then**
        **int** *i* = *from*; *¢* the user's *i* is declared here, and is a copy
        of the current value of *from* *¢*
    **if**
        *p* *¢* the user's *p*, however complex it may be, is
        elaborated here, each time the loop is about
        to be obeyed *¢*
    **then**
        *¢* now comes the user's serial-clause *¢*
        *x* := *x* + *x*1 [*i*]; *¢* the user may access his *i* *¢*
        *p* := *x* < max real/2; *¢* the user may change his *p* *¢*
        *from* := *from* + *by*; *¢* the count is in(de)cremented *¢*
        **go to** *m*
    **fi**
    *fi* *¢* we are now outside the reach of *i*, so the question of its
    value upon exit does not arise *¢*
**end**

You may omit those parts of a loop-clause that you do not need:

<table><tr><td>if for I</td><td>is omitted, there is no I to be accessed</td></tr><tr><td>if from J</td><td>is omitted, <b>from</b> I</td><td>is assumed</td></tr><tr><td>if by K</td><td>is omitted, <b>by</b> I</td><td>is assumed</td></tr><tr><td>if to L</td><td>is omitted, <b>to</b> ∞</td><td>is assumed</td></tr><tr><td>if while P</td><td>is omitted, <b>while true</b></td><td>is assumed</td></tr></table>

In fact, the only part which has to be there at all times is the **do S od.** If this does stand on its own, then the loop is executed indefinitely, unless you jump out of it.
(E8)

ref int h = i; ♦ so that h and i are interchangeable identifiers ♦

<table><tr><td>i := -4;</td><td>for i from 3 by 2 to 3</td><td>while i&lt;0</td><td>do h := h+1 od; ♦ obeyed 0 times ♦</td></tr><tr><td>i := -4;</td><td>from 3 by 2 to 3</td><td>while i&lt;0</td><td>do h := h+1 od; ♦ obeyed 1 time ♦</td></tr><tr><td>i := -4;</td><td>by 2 to 3</td><td>while i&lt;0</td><td>do h := h+1 od; ♦ obeyed 2 times ♦</td></tr><tr><td>i := -4;</td><td>to 3</td><td>while i&lt;0</td><td>do h := h+1 od; ♦ obeyed 3 times ♦</td></tr><tr><td>i := -4;</td><td>while i&lt;0</td><td>do h := h+1 od; ♦ obeyed 4 times ♦</td><td>do h := h+1 od; ♦ ad lib ♦</td></tr><tr><td>i := -4;</td><td></td><td></td><td></td></tr></table>

Vertical readers, please turn to 4.5.

### 3.6. Conformity clauses

<figure><img src="image_78.png" /></figure>

As with case-clauses (3.2.4.3), there is a number of units separated by ","s, but now each one of them is preceded by a "specification", such as *(a a)*: The enquiry-clause yields a value whose mode is of one of the modes in its **union**. If the formal-declarer in one of the specifications matches, or "conforms to", this particular mode, then that specification is chosen and the value is ascribed to its identifier (which is a defining-identifier), if it has one (these identifiers being optional). The unit following the chosen specification is then elaborated, and of course applied occurrences of that same identifier can make the value available inside it. On the other hand, if none of the specifications conforms to the mode of the value, then the **out** clause is elaborated.

Here is an example of a conformity-clause yielding a **bool**:
(E1) union (char, bool, int, real) cbira;

if case cbira

in (bool b): b,

(int i): i > 0,

(real r): r > 0

out false

esac

then ¢ we get here if cbira was not a char and was otherwise
true or > 0, as the case may be ¢

fi

As in ordinary case-clauses, you may omit the **out** clause, you may introduce an **ouse** followed by a new **union** to be tested and a new set of specifications and units, and you may substitute the usual alternatives for **case** etc.:

(E2) union (char, bool) cba, union (int, real) ira;

if (cba | (char): false, (bool b): b

∴ ira | (int i): i > 0, (real r): r > 0

then skip

fi

(Here we must observe that every value referred to by a **ref union** must include within itself an indication to show of which of its permitted modes it currently is. Therefore a **union** (int, real), whilst being a very convenient example with which to illustrate the point, is likely to occupy two words of storage — one for the **int** or the **real**, and one to say which it is. Thus there is no practical benefit in using this mode if the intention is to save storage space.)

A real saving would occur in the following case:

union ([] int, [] real) ir1;

because the elements in these multiples are all **int** or all **real**, and only one additional word is needed to indicate the mode of the whole lot.)

**Vertical readers**, please turn to 5.6.
## 3.7. Collaterality

### 3.7.1. Collateral clauses

Collateral-clauses [R 3.3] include such things as structure-displays (3.4) and row-displays (3.5.1), but the ones we are particularly interested in at the moment are void-collateral-clauses. These consist of a list of two or more void units separated by commas, and enclosed between **begin** and **end**, or between "(" and ")":

$$ (E1) \qquad (x:=I, y:=2, z:=3) $$

These three statements are elaborated "collaterally". There is not likely to be much gain in using collateral-clauses in this way unless your hardware contains three central processors (so that they can do a statement each), or unless you have reason to believe that your compiler is sufficiently clever to discover that they can be done more efficiently in an order other than that in which they were written down. Alternatively, it might be the case that one of the statements was likely to get held up awaiting some event in real time (transput perhaps), in which case the others would be carrying on. This situation is more likely to arise when parallel-clauses are used (see next section). In the meantime we must consider exactly what "collateral" means.

Collateral elaboration occurs, inter alia, in the following situations:

* collateral-declarations

* collateral- and parallel-clauses

* structure- and row-displays

* between the two sides of an assignation or an identity-relation

* between the two operands of a dyadic-operator

* amongst the primary and the actual-parameters of a procedure call.

Suppose two phrases A and B (it could be more) are to be elaborated collaterally. Then the elaboration of A may be merged in time with that of B in a manner left quite undefined by the Report [R 2.1.4.2.e]. So long as the elaboration of A has no side effect upon that of B, and vice versa, then the manner of this merging has no effect on the result — otherwise, anything might happen. Normally, the two elaborations would proceed until both were completed (3.1.4), but if one were terminated by a go to, then the other would be stopped abruptly at whatever stage (if any) it had reached.

In practical compilers, it is probable that A would be elaborated first and then B, or vice versa, but one is not entitled to make any assumptions based on this. Consider the following:
(E2)
begin int i;
proc side = int: (i := 1; i := 2; i);
proc add = (int ii, int jj)int: ii+jj;
print (add(side, side))
end

The two calls on *side* are elaborated collaterally. If one were elaborated entirely before the other (in either order), each would yield the value 2, and 4 would be printed. In the corresponding ALGOL 60 program, this would be the guaranteed result. However, this ALGOL 68 program is perfectly entitled to print 3 as its answer, because *i* is global to *side* and the collateral elaboration of the two calls is quite entitled to be merged [R 2.1.4.2.e] in the following manner:

i := 1;      ¢ on behalf of the first side ¢
i := 2;      ¢ likewise ¢
i := 1;      ¢ this is the second side starting up ¢
i          ¢ on behalf of the first side, which therefore
             yields the value 1, as set by the second side ¢
i := 2;      ¢ the second side ¢
i          ¢ the second side yields 2 ¢

Here is another example:

(E3)
$i := 0;$
$x1[(i += 1; j - 2)] := x2[(i += 1; j - 2)];$
`print (i)`

The two subscripts are to be elaborated collaterally. Suppose their elaborations were merged as follows:

Take $i (=0)$
Add $1 (=1)$
Take $i (=0)$
Add $1 (=1)$
Store in $i (1)$ (because the operator $+:= in$ excludes assignment)
Take $j$
Subtract 2
Store in $i (1)$
Take $j$
Subtract 2
use to index $x1$
use to index $x2$
Thus 1 is printed, even though $i += 1$ has been elaborated twice. In general it may be said that if two identical clauses are to be elaborated collaterally, then the implementation is quite entitled (but not of course bound) to perform the elaboration of only one of them and to assume that the other yields the same result. In other words, a compiler may detect common sub-expressions (such as the $(i += 1; j - 2)$ in E3), and optimise its code accordingly, and if a user has put side effects into these sub-expressions, he has no right to complain if they do not behave as he expected.

So the moral of this story, if you were thinking of use side effects and collaterality is involved, is “Don’t”.

### 3.7.2. Parallel clauses

These are like collateral-clauses, except that you are provided with some control over the synchronisation of the constituent statements. They consist [R 3.3.1.c] of *par* followed by a void-collateral-clause:

(E4) $par(x:=1, y:=2, z:=3)$

However, this example, although legitimate, does not take advantage of the synchronisation facilities provided. To take a more realistic example, suppose we have a procedure which generates lines of output at random intervals:

(E5) **proc item generate** = ( c computes the next item of output,
                       taking a random length of time to do so c);
**mode item** = **struct** ( c a collection of values intended to be printed c );

We wish to print these items of output on a lineprinter which operates in real time (i.e. not disguised by an operating system), and at some fixed number of lines per minute. In order to smooth out the irregular periods between the generation of items (so as, hopefully, to keep both the printer and the central processor busy at all times), we shall put the items into a buffer as they are generated, and take them out at a rate suited to the printer. First let us declare our buffer:

(E6) **int nmb buffers** = c the number of items the buffer can hold c;
[1 : nmb buffers] item buffer;
**int index** := 0, **exdex** := 0; ₩ pointers to items within the buffer ₩
**bool work to be done** := true, printing to be done := true;
 we shall need these in order to know when to stop ₩
Now we must set up some semaphores so that the generating department and the printing department can communicate with each other. There is a special mode provided for this purpose:

(E7) sema free slots, full slots;

A sema has a reference to an int hidden inside it, but you are only allowed to get at it by means of the special monadic operators level, up and down [R 10.2.4]:

<table><thead><tr><th>operator</th><th>priority</th><th>mode of a</th><th>mode of result</th><th>meaning</th></tr></thead><tbody><tr><td>level</td><td>10</td><td>int</td><td>sema</td><td>yields a sema referring to a copy of the int a</td></tr><tr><td>level</td><td>10</td><td>sema</td><td>int</td><td>yields the int referred to by the sema</td></tr><tr><td>down</td><td>10</td><td>sema</td><td>void</td><td>if the int referred to is zero, then the elaboration of this part of the parallel clause is "halted", otherwise the int is reduced by 1</td></tr><tr><td>up</td><td>10</td><td>sema</td><td>void</td><td>the int referred to is increased by 1 and all elaborations previously halted by the operation of down on this particular sema are "resumed" by repeating the tests for zero in their downs</td></tr></tbody></table>

We shall now initialise our semaphores:

(E8) free slots := level nmb buffers; ♦ because we have not generated any items yet ♦
full slots := level 0; ♦ because there are no items waiting for printing ♦

Now we come to our parallel-clause:

(E9) par begin
  ♦ the generating department ♦
  while work to be done
  do
down free slots; `&` halts this department if all the slots
are full. Initially, there are plenty `&`
index modab nmb buffers `+:= 1;` `&` increment index
modulo nmb buffers `&`

buffer [index] `:=` generate;

if `c` there are no more items to generate `c`
then work to be done `:=` false `fi;`

up full slots `&` to enable the other department to get
going `&`

od

, `&` comma to separate the two statements. `&`
`&` the printing department `&`

while printing to be done

do

down full slots; `&` halts this department if there is
nothing to print (as initially) `&`

exdex modab nmb buffers `+:= 1;`

print ( buffer [exdex] );

printing to be done `:=` work to be done `v` index`&`exdex;

up free slots `&` if the other department was halted,
it may now be resumed `&`

od

end

For a more ambitious example of parallel-clauses see R 11.12. For a
general discussion of the use of these semaphores see:

E.W. Dijkstra, Cooperating Sequential Processes, contained in
"Programming Languages", Ed. F. Genuys, Academic Press.
and E.W. Dijkstra, Comm ACM 11 5 May 1968 p 341.

Vertical readers, please turn to 5.7.
# 4. ROUTINES

## 4.1. Procedures and operators

In ALGOL 68, procedures arise out of the structure of the language in a very natural way. Thus routines are values, which therefore have modes. They become ascribed to identifiers or operators by the elaboration of declarations, and they are called in the course of a variety of units.

Therefore, there is hardly a topic in this area which could not have been fitted elsewhere in our orthogonal plan (which is, indeed, why the Report itself contains no chapter on the subject). However, the chapter which you are about to read is not entirely redundant, since we thought it proper in view of their central importance to gather all the information about routines, procedures and operators into one place.

The necessary concepts were introduced in 1.1.4, which indicated how to declare a procedure:

(E1) proc reciprocal = (real a) real:1/a;

and how to call it:

(E2) real x;
x := reciprocal (3.14)

Also how to declare an operator:

(E3) op oneover = (real a) real:1/a;

and how to use it in a formula:

(E4) real x;
x := oneover 3.14

All these matters will be discussed at greater length in 4.2 in the case of procedures, and 4.3 in the case of operators. In particular, note how the right hand side of E1 is the same as that of E3. This is the part which defines precisely what the routine, which is being created in either case, is to do, and is known as a 'routine-text' (4.2.2.1).

### 4.1.1. Standard prelude routines

However, a large proportion of the operators and procedures which you will call in the course of your programs will not have been declared by you in
this way, because they will be already built in to your program by means of
the 'standard-prelude' (1.1). Amongst these you will find procedures for all
the usual mathematical functions (sine, cosine, square root, etc. — the full list
is given in 6.2.2), and operators for all the usual mathematical operations (+,
-, x, ÷, etc., and a lot of not-so-obvious ones — all listed in 6.1., 6.3, 6.5 and
6.7).

Although the procedures declared in the standard-prelude will be just that
— when you call them, certain built-in routines will be entered — this may not
be so for the operators. For example, the operator “+”, used to add two ints
together, is defined in the Report [R 10.2.3.3.i] by the following operation-
declaration:

$$
(E5) \quad op + = (\mathit{int} \ a, \ b) \mathit{int}: a - - b;
$$

If you had used this in your own program, it would have compiled a routine
to do (a - - b), and called it in whenever such a “+” was encountered in a
formula. This is not the intention for the standard-prelude operators. When
this “+” appears in a formula, your compiler should produce, on the spot, the
most efficient possible code to do the same job.

Therefore you need hardly be aware, when using these operators, of the
strange way in which they were introduced into the language, and any such
lack of awareness should be no bar to a full understanding of 5.1.3 where the
use of operators in formulas is fully discussed.

Vertical readers, please turn to 5.1.
## 4.2. Procedure declarations

### 4.2.1. proc declarers

The concept of a "routine" was introduced in 1.1.4. Each routine is of some mode, and for each such mode we can write declarers. There are four classes of routine, categorised according to whether they require parameters or not, and whether they return a value or void.

<table><tr><td>(E1)</td><td>proc void</td><td>¢ no parameters, returns void ¢</td></tr><tr><td>(E2)</td><td>proc int</td><td>¢ no parameters, returns int ¢</td></tr><tr><td>(E3)</td><td>proc ( real, int, ref char ) void</td><td>¢ 3 parameters, returns void ¢</td></tr><tr><td>(E4)</td><td>proc ( real, int, ref char ) bool</td><td>¢ 3 parameters, returns bool ¢</td></tr></table>

This last one would be pronounced in public as:

"procedure-with-(a-)real-parameter-(and-an-)integral-parameter-(and-a-)reference-to-character-parameter-yielding-(a-)boolean"

To say that a routine returns "void" is to say that it returns no useful value.

Formal proc declarers and actual proc declarers look exactly the same [R 4.6.1.o]. (Note also that the declarers specifying the modes of the parameters and of the value returned are always formal.)

The parameters and returned value of a routine can be of any mode whatsoever, including another proc mode:

(E5) proc ( real, proc ( real, int ) void ) proc ( int ) real

A 'procedure' is an external object which upon elaboration yields a routine:

(E6) proc void proca;

is a variable-declaration declaring a ref proc proca. The value referred to by proca is at present undefined, since we have not yet provided a routine for it. However, if it had referred to some routine, then:

(E7) proc void procb := proca;

would have created procb, making it refer to the same routine (initially). Which all goes to show that routines may be assigned and otherwise handled just like values of any other mode.
### 4.2.2. Routines

What, then, is a routine? It is a piece of code somewhere within your program, compiled there as a result of some statements written by you (or maybe it was put there by the standard-prelude (6.2.2)). When a routine is assigned, as in E7 above, there is of course no question of moving pieces of code around inside the computer — it is a pointer to the piece of code that is handled during these operations, but the effect is just the same. Note that there are no operations operating on routines defined within the standard-prelude (with a little ingenuity, you might construct some of your own, but they would probably not be particularly useful).

There are, therefore, two questions that we have to answer:

1. How do we introduce routines into a program, and cause them to be yielded by procedures?

2. How do we "call" them — i.e. cause them to be obeyed?

Major discussion of the second question will be deferred until 5.2.1.

#### 4.2.2.1. Routines texts

A 'routine-text' [R 5.4.1] is used to create a routine. It may stand, inter alia, as the actual-parameter of an identity-declaration, or of a call (see E18 below), or as the RHS of an assignation. Here is a routine-text yielding a routine of mode `proc(real, real) real`:

(E8) `real a, real b) real: a+b`

Please note that `(real a, real b) real` is not a declarer such as `proc(real, real)real` is (declarers do not contain identifiers). The `real a` and the `real b` occurring in E8 are formal-parameters, such as you would expect to find on the LHS of an identity-declaration (2.2.1), and the two `reals` in these formal-parameters and also the `real` specifying the mode to be returned are therefore formal-declarers. The `a+b` in E8 is a strong unit (5.1.0.2) and forms the body of the routine.

Now we may use E8 in an identity-declaration, to declare a `proc(real, real) real`:

(E9) `proc(real, real) real sum = (real a, real b) real: a+b;`

Rather a cumbersome way of adding two `reals` together, and rather a cumbersome way of declaring it, too. There are two contractions we can use to
shorten it. Firstly, the reals in the two formal-parameters of the routine-text may be gathered together in the familiar (2.1.2) fashion (i.e. (real *a*, *b*)). Then, there still being considerable redundancy, all of the formal-declarer after the proc may be omitted [R 4.4.1.b], leaving:

(E10) proc sum = (real *a*, *b*) real: *a* + *b*;

which really is about as short as you could expect. In this form it is known as a 'routine-identity-declaration'. Likewise:

proc refsum `&` of mode ref proc etc `&` := (real *a*, *b*) real: *a* + *b*;

which was a 'routine-variable-declaration'.

When there are no formal-parameters, the routine-text becomes very simple, as in this proc real:

(E11) real: *x* + 3.14

which may appear in an identity-declaration with the usual routine contraction:

(E12) proc xplus = real: *x* + 3.14;

Finally, there is one more contraction to be used where several procedures are to be declared (but please use it only for short snappy ones):

(E13) proc iplus = int: *i* + 3, zplus = compl: *z* + 1 i 1;

The part after the ":" in a routine-text can be any strong unit (Chapter 5) yielding the required mode. Most often it will be some form of ENCLOSED-clause (3.2.4), as in the following example in which we also illustrate a routine-text returning void:

(E14) proc pqrs = (ref real *a*, *b*) void: (*i*<0 | *a* := 3.14 | *b* := 3.14);

Note that in a routine-declaration the RHS must always be a routine-text. If we go back to the uncontracted identity- or variable-declaration, this restriction does not apply and we can, for example, make the routine to be ascribed or assigned dependent upon some condition:

(E15) proc void pq = (*i*<0 | void: *a* := 3.14 | void: *b* := 3.14);

Here we have two routines available. Which of the two is ascribed to pq will depend on the value of *i* at the time E15 is encountered. Please compare this example carefully with E14, in which there is only one routine which tests *i* each time it is called.

A routine-text is a quaternary (5.1.0.1), and this determines where it may
be used (thus if it was needed as the operand of a formula (5.1.3) it would need to be enclosed between “(” and “)”).

### 4.2.2.2. Calling

A routine with formal-parameters can be called by providing it with actual-parameters to match its formal ones. Within the context of E10 we could put:

(E16) $a := sum(x, y)$

$x$ and $y$ are the actual-parameters of this call. What happens next is just as if the routine-text had been transformed into a cast containing an identity-declaration to match each formal-parameter with its actual counterpart. The elaboration of the call is equivalent to the elaboration of that cast. Applying this process to E16 and E10, we get:

```
real (
    real a = x, b = y;
```

after which comes the body of the routine:

```
a+b
)
```

Observe how the `(` and the `)` demarcate a new range, so that the formal-parameters $a$ and $b$, to which real values have been ascribed for the duration of this call, may not be confused with any occurrences of $a$ and $b$ elsewhere. Observe also that real $a = x, b = y$ is a contracted collateral-declaration, so that $x$ and $y$ are elaborated collaterally (3.7.1).

In this example, real values were ascribed to the formal-parameters $a$ and $b$, and so it would have been illegal to try to assign to them from within the routine. In ALGOL 60, this would have been known as “call by value”. If we do wish to alter the value referred to by a formal-parameter, then that parameter must be of a mode that refers to something, as in E14 which permits the following call:

(E17) $pqrs(x, y)$

which will assign 3.14 to either $x$ or $y$, according to the value of $i$ at the time. We term this “call by reference”. In ALGOL 60, you would have had to use (or misuse) “call by name” for that one.

To get some other effects of the ALGOL 60 call by name, however, you must declare your procedure with `proc` mode parameters:
(E18) proc series = (int k, proc (int) real term) real:
    begin real sum := 0;
    for j to k do sum += term (j) od;
    sum
    end;

This sums the terms of some series from 1 to k. When it is called, the actual-parameter provided for the term can be any unit that yields a proc (int) real, and very commonly this will be a routine-text.

(E19) x := series (100, (int i) real: 1/i)

During a call of this routine, the procedure ascribed to term (in this case the routine-text) is called once each time round the loop-clause. This is how, in ALGOL 68, we achieve the effect of Jensen's device.

See 5.2.1 also for other examples and further discussion of calls.

A routine without formal-parameters is called by means of a coercion known as deproceduring. This is described fully in 5.2.1, but here is a brief example:

(E20) begin
    real x;
    proc pp = void: x := 3.14;
    begin
        real x := 0;
        pp;      & pp is called &
        print (x) & prints 0.0 &
    end;
    print (x) & prints 3.14 &
end

When *pp* is called, the routine from *void*: x := 3.14 is entered. Note, however, that the name *x* assigned to by this routine is (as we hope you would expect) the one declared in the outer range, and not the one declared just before the call.

### 4.2.2.3. Recursion

Suppose, now, that a routine happens to contain a call on itself (either directly, or via a chain of calls on other routines which eventually calls the same one again). Are there any problems? In some programming languages there may be, but not in this one. It all works out normally, just like you
would expect. You will find several examples of such recursion in this book, notably in 8.7.1. Here is another one:

(E21) **begin**

proc blocked = (int x, y) bool: c A description of a maze, centred at (0, 0) with entrance at (0,100). Yields true if the point (x, y) is inaccessible (part of the walls). The maze is presumed to contain no cycles. c;

int x := 0, y := 100, d := 0; & starting coordinates and direction &

proc maze = bool :

if blocked (x, y) then false

elif x = 0 \ y = 0 then true

else int presx := x, presy := y, presd := d, i := 0;

loop: i := i + 1;

x := presx + ((d := (presd + 2 + i) mod 4) + 1 | 0, -1, 0, +1);

y := presy + (d + 1 | -1, 0, +1, 0);

if maze then true else (i < 3 | go to loop); false fi

fi;

print (if maze then "Maze is solved" else "No route to centre "fi )
end

Clearly, *maze* can call itself recursively to a considerable depth. Now *maze* contains declarations for the variables *presx*, *presy*, *presd* and *i*, which must be elaborated whenever it is called (two trivial cases apart). This means that four locations must be reserved on the stack (1.2.2.3). Next, *maze* calls itself recursively, and we meet these declarations again. Do we get the same four locations? Of course not! We reserve another four on the stack, and the first four become inaccessible until such time as we return to the particular call of *maze* in which they were created. Then we will find that their values have not been touched since we left them.

So, by the time *maze* has called itself to a depth of 20, there are 20 instances of these four variables on the stack, and their values form a complete record of how we got from the entrance to where we are. So, if we replace the last line but one of *maze* by:

if *maze* then *print((presx, presy, newline)); true else (i < 3 | ...*

then we shall get printed a complete set of directions showing how to get out
again.
### 4.2.3. Scopes of routines

The following example should be compared carefully with 3.2.2. E3:

(E22)

begin **proc void** *pp*; real *y*;
    begin real *x*; proc *p* = void: *y* := *x*;
        *x* := 2.0;
        *p*;      // *p* is this all right. 2.0 is assigned to *y*
        *pp* := *p*; // *p* this one is going to cause trouble
    end;
    print(*y*); // *p* no complaints
    *pp*;        // *p* tries to assign *x* to *y*, but who is *x*? //
    print(*y*) *p* now what? //
end

In an assignation, the scope of the RHS must be at least as old as that of the LHS, and in the case of `pp := p` above, it was obviously the scope of the routine ascribed to `p` (i.e. `void: y := x`) that was too new.

In fact, the scope of a routine corresponds to the smallest range containing a declaration of an identifier or a bold word (2.3 or 4.3.2) which is used inside that routine [R 7.2.2.c] (i.e. the inner range in the above example because the routine contained an *x*). There are two small exceptions. A mode-indication used inside the routine as a formal-declarer (i.e. not as an actual one) does not count for this purpose, neither does an applied-operator whose only crime is to identify a priority-declaration (4.3.1) outside.

In both this example, and in 3.2.2. E3, the trouble could have been caught by a check at compile time, but in the following example a run time check would be necessary:

(E23)

begin **ref real** *xx*, proc *copy* = (ref real *a*) ref real: *a*;
    begin
        real *x* := 2.0;
        *xx* := *copy* (*x*)
    end;
    print(*xx*)
end

**Vertical readers**, please turn to 5.2.
### 4.3. Operation declarations

The operators used in formulas (5.1.3) are either symbols built in to the language for the purpose, or bold words (1.3) invented by the user. (Note that a bold word used in a mode-declaration (2.3) may not, in that reach (3.2.1), be used for an operator.) (Note also that the built in symbols may all be used for either monadic- or dyadic-operators, except for the symbols <, >, /, =, x, and * which may not be monadic [R 9.4.2.1].)

In order to be used, an operator must yield a routine, and if it is to be used as a dyadic-operator it must have a priority too. Now several routines may, at one and the same time (subject to a restriction that will be discussed below in 4.3.3), be ascribed to a given symbol (or bold word), but that symbol (or bold word) may only have one priority. Therefore, before a symbol can be used as a dyadic-operator, it must be given a priority (unless it has already acquired one in the standard-prelude [R 10.2.3.0]).

#### 4.3.1. Priority declarations

There are 9 available priority levels for symbols to be used as dyadic-operators (for convenience, we classify monadic-operators as having priority 10 in Chapter 6, but this is purely our own convention). We associate a priority with a symbol (for the duration of some range) thus [R 4.3.1]:

$$ (E1) \quad \textbf{prio min} = 9; $$

Priority-declarations may be incorporated into collateral-declarations:

$$ (E2) \quad \textbf{prio min} = 9, \textbf{prio max} = 9; $$

and this may be contracted into:

$$ (E3) \quad \textbf{prio min} = 9, \textbf{max} = 9; $$

#### 4.3.2. Operation declarations

An operation-declaration looks rather like an identity-declaration:

$$ (E4) \quad \textbf{op} (\textbf{real, real}) \textbf{real min} = (\textbf{real } a, b) \textbf{real: } (a < b | a | b); $$

The RHS of this one is a routine-text (4.2.2.1), but in general it is an actual-parameter (2.2.1) - so if you were trying to be very posh you might try to organise yourself some other unit which (after suitable coercion, of course) would yield a proc(real, real)/real. Normally, however, a routine-text is as far as you will ever need to go, in which case you may then immediately contract
it as with routine-declarations (cf 4.2.2.1. E10):

$$ (E5) \quad \texttt{op min} = (\texttt{real } a, b) \texttt{ real: } (a < b | a | b); $$

The operator min now works for pairs of reals. However, we may wish it to work for other combinations:

$$ (E6) \quad \texttt{op min} = (\texttt{int } a, b) \texttt{ int: } (a < b | a | b), $$

$$ (E7) \quad \texttt{min} = (\texttt{int } a, \texttt{ real } b) \texttt{ real: } (a < b | a | b), $$

$$ (E8) \quad \texttt{min} = (\texttt{real } a, \texttt{ int } b) \texttt{ real: } a \texttt{ min real } (b); $$

E8 was trying to be clever by using the version of min already declared in E5. It is an interesting example of the use of a cast (5.1.1.3) but not an efficient way of doing a job, as E7 was. Note the contraction whereby the ops have been gathered together (cf 4.2.2.1. E13).

Now min yields four routines, but this is only the start of it. Now there are all the combinations of long reals and long ints (2.7.2), and no doubt sensible meanings could be found for min when operating upon chars, strings and all sorts of things.

min is a dyadic-operator (so far), and as such yields routines which have two formal-parameters. Monadic-operators, of course, yield routines with one formal-parameter:

$$ (E9) \quad \begin{array}{ll} \texttt{op min} = (&\texttt{[] real } a1) \texttt{ real:} & \\ \texttt{begin real } x &:= \texttt{max real } \phi \texttt{ 6.2.1 } \phi; \\ & \texttt{for } i \texttt{ from } \texttt{lwb } a1 \texttt{ to } \texttt{upb } a1 \texttt{ do } (a1 [i] < x | x := a1 [i] ) \texttt{ od;} \\ & x \texttt{ end;} & \end{array} $$

Routines yielded by operators are entered when those operators are encountered in the elaboration of formulas [R 5.4.2]. For a full understanding of formulas, you should consult 5.1.3. It will suffice here to show how the operands of the formula are matched up to the formal-parameters of the yielded routine (having selected the right routine to match the modes of the operands, of course). This process is identical to that used when procedures with parameters are called (4.2.2.2). So, if we have the formula:

$$ (E10) \quad \texttt{i min } x $$

we first select the E7 version of min, and then construct the following collateral-declaration:

$$ \texttt{int } a = i, \texttt{ real } b = x; $$

In the reach of this declaration, $(a < b | a | b)$ is elaborated, and the real result becomes the value yielded by the formula.
### 4.3.3. Identification of operators

The identification of identifiers was described in 3.2.3, and the purpose and method of identification of operators are essentially similar. Consider the identification of `min` in:

<figure><img src="image_79.png" /></figure>

Firstly, you must identify all the applied occurrences of `min` in the formulas with the defining occurrences of `min` in the priority-declarations. This results in the dotted lines to the left hand side of E11.

Secondly, you must identify all the applied occurrences of `min` in the formulas with the defining occurrences of `min` in the operation-declarations. But you must only accept, in your search, a defining occurrence the modes of whose formal-parameters can be firmly coerced from the modes of the operands of the formula [R 7.2.1]. This results in the lines on the right of E11.

However, let us now try to declare another version of `min`:

$$ (E12) \quad \mathbf{op\ min} = (\mathbf{ref\ real}\ a, b) \mathbf{ref\ real}: (a < b | a | b); $$

The purpose of this one is to determine which of two names (of mode `ref real`) refers to the smaller value. Let us use it in a formula:

$$ (E13) \quad x \min y $$

But Oh dear! Doesn't this also identify the version of `min` declared in E5 (in a formula, the operands are firm, and so `x` and `y` can be dereferenced in this example (5.1.0))?

Clearly, it must be forbidden for E5 and E12 to occur in the same reach. This is expressed by saying that the modes of the formal-parameters of two declarations of the same operator in the same reach must not be "firmly
related” [R 7.1.1], i.e. one of them, or a component mode of one of them (if it is a **union**), must not be firmly coercible to the other. Since **ref real** (in E12) is firmly coercible to **real** (in E5), these certainly do not pass the test.

However, even if two declarations are in different reaches, as they are in E11, and they are firmly related, then the one in the inner reach renders invisible the one in the outer reach. Thus you could not have written, immediately after $xx := x \min y$ in E11, $a := x \min 2.0$. It certainly could not have identified the **min** declared for two **ref real** parameters, and it is not allowed to see the other one. On the other hand, $k := i \min 2$ would have been all right in this position. This additional restriction simplifies implementation of the language and is unlikely to affect the average user, since it is more likely that such an identification would indicate an error on his part, than that it would be his real intent.

**Vertical readers**, please turn to 6.3.
### 4.5. Row-of parameters

Consider routines of modes such as `proc ( [ ] real) void`. When such a routine is called, the compiler may be obliged to take a copy of the value of the actual-parameter — in general a time consuming operation — just in case the body of the routine should contrive in some way to alter the original:

$$ (E1) \quad \begin{array}{l} [0:99] \text{ real } x1; \\ \quad \text{proc } a2 = ( [ ] \text{ real } b1) \text{ void: for } i \text{ to } 99 \text{ do } x1[i] := b1[i-1] \text{ od;} \\ \quad a2(x1) \end{array} $$

The intention and effect of this example is not to make every element of `x1` a copy of `x1[0]`, which is what would have happened if `b1` had not yielded a copy of the value of `x1` at the start of the call.

However, cases such as this are rare, and a decent implementation will postpone making the copy until the problem actually arises, if at all. But not all implementations are decent, and so it may be wiser to declare your formal-parameter as a `ref [ ] real`. Then, as call, it is only a name which has to be passed to the routine, which uses it to access the original multiple value that it refers to. However, if a routine is provided with a name, it is entitled to be told whether the multiple value referred to is fixed or flexible:

$$ (E2) \quad \begin{array}{l} \text{proc } a5 = (\text{ref } [] \text{ real } b1) \text{ void: } XXXXX; \\ \quad \text{proc } a6 = (\text{ref flex } [] \text{ real } b1) \text{ void: } XXXXX; \end{array} $$

For further discussion of this point, see 8.5.

**Vertical readers**, please turn to 5.5.
## 4.7. Jumps

We have informally been using jumps in this book right from the start, but mainly only in places where we had not yet introduced choice-clauses (3.2.4) or loop-clauses (3.5.2). Since these already provide powerful and adequate facilities for controlling the flow of your program, jumps are hardly necessary in ALGOL 68. Their main legitimate uses are for premature exits from loop-clauses and from event routines (7.4.4).

### 4.7.1. Simple jumps

We have already seen (3.1.2) that labels may appear anywhere in a serial-clause provided no declarations come afterwards:

(E1) labl:

A jump to a label consists of **goto** (or **go to**) followed by the label that is to be identified (3.2.3), or simply just of that label by itself:

(E2)
**goto labl**
**go to labl**
**labl**

The effect of the jump is to cause the unit following that label to be elaborated next. A jump may only occur in a strong context (its mode is irrelevant, but is automatically regarded as the mode expected for syntactical purposes).

### 4.7.2. Procedured jumps

In some other languages, there is a mode **label**, and one may assign labels to **label** variables and subsequently jump to them. In ALGOL 68, however, **procs** are used for this purpose [R 5.4.4.2]:

(E3)
**proc void ppp;**
**ppp := goto stop**

The elaboration of this constructs the routine

**void: goto stop**

and assigns it to *ppp*, just as if we had written

(E4)
**ppp := void: goto stop**

An interesting application of this facility can be used to realise the equivalent of the ALGOL 60 **switch** facility:
(E5) `[] proc void switch = (e1, e2, e3);` `¢` a multiple of `procs`. `e1`, `e2` and `e3` are labels ¢ `switch [i] ¢` jumps to the label selected by `i ¢`

In fact, if a jump appears in any strong context where a procedure without parameters is expected (no coercions allowed), this is what happens. In all other contexts, the jump is simply obeyed immediately. Thus we may distinguish between

(E6) `x := if p then y else stop fi`

and

(E7) `task1 := if p then void: print ("P WAS TRUE") else goto stop fi` ¢ see Appendix 2 for `task1`. `if p is false`, we assign `void`: `goto stop` to `task1`, but we do not go there yet ¢

Vertical readers, please turn to 5.7.
# 5. UNITS

## 5.1. Simple units

‘Units’ (also termed ‘unitary-clauses’) are the entities in the language which actually get things done. The simplest example of a unit is the simple type of assignation (e.g. $x := y + 2.4$) which we have used many times already. However, examples much more complex than this can be constructed in accordance with a set of rules which it is the purpose of this chapter to describe. (The corresponding definitions are mostly to be found in R5.)

### 5.1.0. Coercion

#### 5.1.0.1. Coercends

The basic building blocks out of which units are made are known as ‘coercends’, of which there are 16 types, arranged in a hierarchy as follows:

quarternaries (or units)

assignations

routine-texts

identity-relations

*jumps

*skip

tertiaries

formulas

*nil

secondaries

selections
generators

primaries

denotations
applied-identifiers

casts

calls

slices

format-texts

*ENCLOSED-clauses

<footnote>* Strictly speaking, these units are not coercends, since they cannot be coerced.</footnote>
A unit can be any quaternary. Right at the bottom are ENCLOSED-clauses (as $(a+b)$ in $x := y \times (a+b)$) which are themselves made up of further units (as described in 3.2.4), so that the definition of the whole setup is recursive.

Now the elaboration of a unit (i.e. of a coercend or of an ENCLOSED-clause) has two effects.

Firstly, it must yield a value (e.g. the value of the formula $2+3$ is 5). This value will be of some mode, possibly void, uniquely determinable at compile time. If the mode is void, then the unit is a 'statement'; otherwise it is an 'expression'. Secondly, some other actions (independent of what is yielded) may take place (e.g. in $x := 2.4$, the value 2.4 is assigned to $x$).

### 5.1.0.2. Coercion

Now the a priori mode of a coercend may have to be coerced (see 1.1.6) into the mode that is required by the "context" in which that coercend appears [R 6.1]. Thus, the a priori mode of 2 is int. If 2 occurs in the context $x := 2$, then the expected mode (after the $x :=$) is real. When this assignation is elaborated, then, the integral value 2 must be coerced into the real value 2.0 before the assignation can proceed. Fortunately this particular coercion (which is known as "widening") is permitted in this particular context and this assignation is therefore legitimate. The question as to whether any one of the 6 permissible coercions may be applied in a particular case depends upon the context. For this purpose, contexts are divided into 5 classes:

* strong
* firm
* meek
* weak
* and soft

All 6 coercions may be applied in strong positions. During the rest of this chapter, as we describe each form of unit, we shall indicate the strength of the contexts occurring in it. Here, in the meantime, is a summary:

<table><tr><td rowspan="10">strong contexts</td><td>The RHS of identity-declarations (2.2.1)</td></tr><tr><td>The actual-parameters of calls (5.2.1)</td></tr><tr><td>The RHS of initialized variable-declarations (2.2.3)</td></tr><tr><td>The RHS of assignations (5.1.4.1)</td></tr><tr><td>The ENCLOSED-clauses of casts (5.1.1.3)</td></tr><tr><td>The units of routine-texts (4.2.2.1)</td></tr><tr><td>Statements (must yield <b>void</b>) (5.7.0.1)</td></tr><tr><td>All constituents but one of a balanced clause (5.2.0.1)</td></tr><tr><td>One side of an identity-relation (5.7.4)</td></tr></table>
<table><tr><td>firm contexts</td><td>Operands of formulas (5.1.3)<br>In effect, the actual-parameters of transput<br>calls (7.1.1, 7.1.2)</td></tr><tr><td>meek contexts</td><td>Trimscripts (must yield int) (5.5.1.3)<br>Enquiries (3.2.4.2, 3.2.4.3, 3.5.2, 3.6)<br>Primaries of calls (e.g. sin in sin(x)) (5.2.1)</td></tr><tr><td>weak contexts</td><td>Primaries of slices (e.g. x in x[i]) (5.5.1.3)<br>Secondaries of selections (e.g. z in re of z) (5.4.2)</td></tr><tr><td>soft contexts</td><td>The LHS of assignations (5.1.4.1)<br>The other side of an identity-relation (5.7.4)</td></tr></table>

A complete chart of all the coercions is given below. The way to use this chart is as follows. Consider first the mode (a priori) of the available coercend and secondly the mode (a posteriori) required by the context. Then you must find a route following the arrows on the chart that will, through a sequence of intermediate modes, take you from the first to the second. If the coercion is possible, then there will be such a route (if there are several routes, they will always be found to be equivalent).

Suppose, for example, that in a strong context you have (a priori) a coercend of mode `proc ref bool` and what you really need (a posteriori) is a value of mode `[] union (real, int, bool)`. Then there is indeed a route between them, but the simplest way of describing it to you will be to introduce a fictitious operator to represent each coercion on the way, as suggested in 1.1.6 (of course these operators are not really part of ALGOL 68). Thus the required value is obtained by the following operations on the coercend:

### ROW/UNITE/DEREFERENCE/DEPROCEDURE/(coercend)]]]]

and you will encounter these operations (from the innermost to the outermost) as you follow the route. Doubtless you will be relieved to hear that coercions do not invariably get so complex.

The change of mode brought about by each of these fictitious operators is given in the chart. Their effect upon the elaboration of the program will be found at appropriate points in this introduction, as follows:

<table><tr><td>voiding</td><td>5.7.0.1</td></tr><tr><td>rowing</td><td>5.5.0</td></tr><tr><td>widening</td><td>5.1.0.4, 5.4.0, 5.7.0.2</td></tr><tr><td>uniting</td><td>5.6.0</td></tr><tr><td>dereferencing</td><td>5.1.0.3, 5.4.2, 5.5.1.3</td></tr><tr><td>deproceduring</td><td>4.2.2.2, 5.2.0.2, 5.2.1</td></tr></table>
<figure><img src="image_80.png" /><figcaption>COERCION CHART</figcaption></figure>

<footnote>* nonproc is all modes except proc amode and refs proc amode.</footnote>

<footnote>** The corresponding longs and shorts versions can also be widened.</footnote>

<footnote>*** Comorfs are assignations and casts. The rest are morfs. See 5.2.1.</footnote>
If you cannot find a suitable route through the maze simply because your context is not strong enough, then all is not lost. A device known as a 'cast' has been provided wherein you first state the mode you would like to have (a posteriori), and then strongly coerce yourself into it regardless. Casts are described in 5.1.1.3 below. They are particularly useful for dereferencing in soft contexts and for widening in firm ones.

### 5.1.0.3. Dereferencing

We have already explained in 1.1.2.1 and in 2.1.2 how a declaration such as real x; causes a location in the memory to be reserved (or "generated") for a real value, the name which refers to that value being ascribed to the identifier x. Thus, the value yielded by x is a name of a priori mode ref real.

Now, very frequently, what we want is the real value stored in the location referred to (as x in the assignment y := x) and what we have got is its name. We must therefore have resort to the coercion known as "dereferencing".

Dereferencing [R 6.2] is permitted in any context that is strong, firm, meek or weak (which is almost everywhere). (A slight restriction in the case of weak positions will be discussed in 5.4.2.) The effect is to remove one ref from the a priori mode, and to yield the value of the thing that was named. If this value is in turn another name, then further dereferencing may be required.

Thus if the ref real identifier x stands in a context that is strong, firm or meek, and if the expected mode is real, then the value yielded is the real value that x refers to.

### 5.1.0.4. Widening

Consider:

(E1) $x := i$

Widening [R 6.5] is used to turn an int value into a real value (also a real value into a compl value (see 5.4.0) and some further cases in 5.7.0.2). In this example, therefore, the ref int i is first dereferenced to yield an int value, which is then widened to yield the corresponding real value, which can then be assigned to the name x.

We shall now consider the simpler forms of coercend, starting with the primaries:

#### 5.1.1. Primaries

We shall consider three forms of unit here-denotations, identifiers and casts.
### 5.1.1.1. Denotations

Denotations are those entities which, in earlier languages, would have been known as "literals" or "constants". The following examples show some legitimate denotations, together with the a priori modes of the values that they yield [R 8.1].

<table><tr><td>Yielding <b>int</b></td><td>2; 1024; 123; 0123</td></tr><tr><td>Yielding <b>real</b></td><td>12.3; 1.23<sub>10</sub>1; .123<sub>10</sub>+1; 0.123e+1; 1230e-1<br>0.00123; .00123; 123.0; but not 123.</td></tr><tr><td>Yielding <b>bool</b></td><td><b>true</b>; <b>false</b></td></tr><tr><td>Yielding <b>char</b></td><td>"a"; "B"; "1"; ""; "_"; "" for a space symbol;<br>"""" for a (single) quote symbol</td></tr></table>

From a study of these examples, you should be able to construct any other denotation that you might require.

For *string denotations* see 5.5.1.1, for the *void denotation* see 5.6.1 and for *bits and long denotations* see 5.7.1.

### 5.1.1.2. Applied identifiers

An identifier standing as a unit constitutes an applied occurrence (1.1.5) of that identifier. Somewhere, that same identifier will have been declared (at its defining occurrence). These two occurrences must be correlated since the a priori mode of the value yielded when it stands as a unit is the same as the mode with which it was declared. The exact method of correlation is considered in 3.2.3.

### 5.1.1.3. Casts

Suppose the operator ◊ had been defined for pairs of *reals*, but not for *ints*, and suppose you wanted the formula:

$$ (E2) \quad x \diamond i $$

which would not then be allowed. *i* cannot be widened because its context is only firm. If only it were strong. Let us therefore make a mould the shape of a *real*, and melt up our *int*, and cast it into the required shape:

$$ (E3) \quad x \diamond \text{real}(i) $$

This is all right. *real(i)* is a 'cast' [R 5.5.1]. The formal-declarer *real* specifies that it shall yield a *real*, which suits the ◊ operator. Immediately after the
formal-declarer the context is strong, and an ENCLOSED-clause is expected.
Thus the **int i** may be widened to **real** and everyone is happy.

Other examples of the use of casts will be given in 5.2.4. Ingenious users
will find many other applications. For example, in transput (see 7.1), given
i = 1234:

$$
\begin{array}{ll}
\text{(E4)} & \mathit{print}(i); \quad \mathcal{c} \text{ will print } 1234 \quad \mathcal{c} \\
& \mathit{print}(\mathit{real}(i)); \quad \mathcal{c} \text{ will print } 1.234_{10} + 3 \quad \mathcal{c}
\end{array}
$$

5.1.2. Secondaries

Discussion of secondaries will be postponed until Section 5.4.2.

5.1.3. Tertiaries—formulas

(The reason why we sometimes prefer to talk of formulas rather than
formulae is to be found in the Report at 1.1.4.2.a, but we would not
recommend that you should read that just yet.)

The following are examples of ‘formulas’:

$$
\begin{array}{l}
\text{(E5)} \quad x - 2 ; x \diamond y \mathcal{c} \text{ if a meaning for } \diamond \text{ has been declared } \mathcal{c} ; \\
\qquad x \times a + b ; x \times (a + b) ; -2
\end{array}
$$

It will be seen that the essential feature of formulas is that they contain
operators which operate upon operands [R 5.4.2].

If a formula contains more than one operator, then there is an implied
bracketing which ensures that each dyadic-operator has two clearly defined
 operands, and each monadic has one. In order to assist with the implied
 bracketing, each dyadic-operator has an associated priority in the range of 1
 through 9, all monadic-operators effectively having priority 10. For example,
 "↑" has priority 8, "×" and "/" have 7, and "+" and "-" have 6. The rule is
 that the operators with the highest priority are always considered first. Thus:

$$
(E6) \quad x \times a + b \quad \text{means} \quad (xxa) + b
$$

$$
(E7) \quad -a+b \quad \text{means} \quad (-a)+b \text{ (because the "-" here is monadic)}
$$

$$
(E8) \quad +4-2\uparrow2 \quad \text{means} \quad (+4)-(2\uparrow2) \quad \text{(and yields } 0\text{)}
$$

$$
(E9) \quad -2\uparrow2+4 \quad \text{means} \quad ((-2)\uparrow2)+4 \quad \text{(and yields } 8\text{)}
$$

$$
(E10) \quad 4 + -2\uparrow2 \quad \text{means} \quad 4 + ((-2)\uparrow2) \quad \text{(and yields } 8\text{).}
$$

We agree that E8 and E9 are confusing, but it was thought that to have
some dyadic-operators of priority higher than the monadics would have been
even more so. The operator “↑”, as in $a↑b$, should not be thought of as equivalent to the usual mathematical notation for “to the power” as in $a^b$, which is itself a notation for a function such as $pow(a, b)$.

Where several operators of the same priority occur together, an additional rule is needed. Thus for dyadic-operators:

$$ (E11) \quad i - j + k - m + n $$

means

$$ (E12) \quad (((i - j) + k) - m) + n $$

Likewise for monadic-operators:

$$ (E13) \quad + \text{abs entier} - x $$

means

$$ (E14) \quad +/(\text{abs}/\text{entier}(-x))) $$

The priority and meaning of each operator are either built into the standard-prelude (6) or library-prelude (1.1) or are defined by the user (1.3.3.2 and 4.3).

- The mode(s) of the operand(s) in a formula must match the mode(s) for which its operator has been defined. For example, the dyadic-operator “+” is defined (6.1.2) to do a variety of things, amongst which is a definition which states that if its first operand is **real** and its second operand is **real**, then it yields a **real** value which is to be the sum of its two operands (within the accuracy permitted by the implementation). A separate definition states that if its first operand is **int** and its second is **int**, then it yields an **int** value, and there are ten other similar definitions, not to mention three more for its monadic counterpart (6.1.1).

An operand can be any tertiary except **nil**, provided it is of the required mode. E.g. it can be another formula (as in the implied bracketing examples above), a selection, a denotation or an **ENCLOSED**-clause, but it cannot be an assignation because an assignation is not a tertiary (see 5.1.0.1). Thus if you wanted to operate upon an assignation, you would have to make it into a closed-clause thus:

$$ (E15) \quad x + (b := a \times y) $$

The tertiary which constitutes an operand is in fact firm, and the permitted coercions therefore include dereferencing, but not widening. Thus in:

$$ (E16) \quad x + y $$
the names x and y are first dereferenced to yield two real values, which are
then added to yield the real value of the formula.

Consider also:

$$
(E17) \quad x := i + j
$$

i and j cannot be widened because of the firm context, but the version of “+”
to add two ints can be used. Then the value of the whole formula i+j, being of
mode int, can be widened to real.

$$
(E18) \quad x := i + y
$$

Here again, *i* cannot be widened in order to be added to *y*. The formula *i*+*y* is
only valid by virtue of the fact that the operator “+” is also defined (6.1.2)
for the case of an **int** plus a **real** yielding a **real**.

5.1.4. Quaternaries

5.1.4.1. Assignations

An ‘assignation’ [R 5.2.1] is one of the commonest forms of unit. It
consists of two parts—a left hand side (its ‘destination’) and a right hand side
(its ‘source’). Consider the following example:

$$
(E19) \quad x := y + 3.14
$$

The LHS (x in this example) is subject to the following restrictions:

a) It must yield a name (i.e. its mode must be **ref amode**; in the example above *x* was **ref real**).

b) It must be a tertiary (in the example *x* was an applied-identifier; a formula is also possible but in fact few operators yield names (but see 6.3)).

c) Its context is soft, which means in particular that no dereferencing is allowed (unless you use a cast).

Application of these rules completely determines the mode of the value
referred to by the name yielded.

The RHS (*y* + 3.14 in the example) therefore has considerable freedom,
the rules being the following:

a) It must yield a value whose mode is the same as that of the value
referred to by the left hand side (in the example a real value is yielded,
which is in agreement with the *ref real* mode of the left hand side).

b) It can be any quaternary, which means it can be any coercend or any ENCLOSED-clause, provided a suitable mode is yielded (in the example it was a formula).
c) Its context is strong, which means that any known coercion can be applied in order to obtain the required mode (in particular, both widening and dereferencing can be used).

d) It has a scope restriction, but this is described in 3.2.2.

Consider:

$$ (E20) \quad x := y $$

Both $x$ and $y$ are, a priori, names (of mode ref real). $y$ must be dereferenced to yield a real value. The value formerly referred to by $x$ is then superseded by this real value.

$$ x := a + b $$

In this case the RHS is the formula $a + b$, which already yields a real value. No dereferencing is therefore needed (note, however, that $a$ and $b$ were in fact dereferenced during the elaboration of the formula itself).

Since any quaternary can stand for the RHS of an assignation, it follows in particular that another assignation can so stand. It is therefore necessary to specify what value (and of what mode) is to be yielded. In fact, the value yielded by an assignation is the value yielded by its LHS, which is always of mode ref amode. Consider the following:

$$ (E21) \quad a := b := x := 2.4 $$

Let us first insert the implied bracketing (which, as you will observe, is not that of a dyadic-operator (see 5.1.3. E12)):

$$ (E22) \quad a := (b := (x := 2.4)) $$

First of all, the real value 2.4 is assigned to $x$. The value of $x := 2.4$ as a whole is the name $x$ which, being of mode ref real, must be dereferenced before the value to which it refers (which is now 2.4, of course) can be assigned to $b$. The value of this assignation is the name $b$, the value referred to by which (2.4 again) can now be assigned to $a$. Thus, everybody lands up by referring to his private instance of 2.4. The formula $x + (b := axy)$ given in example E15 causes the product $axy$ to be assigned to $b$. $x$ and the new value now referred to by $b$ are then added together.

### 5.1.4.2. skip

skip is a special form of unit. As a statement, it is a dummy. In other strong contexts, it yields an undefined value of the mode demanded.
Note that it is never subject to coercion and that it may only occur where the context is strong.

Vertical readers, please turn to 6.1.

## 5.2. Balance and call

In this section we consider balancing, procedure calls, and also some further examples of coercends involving names.

### 5.2.0. Coercion

#### 5.2.0.1. ENCLOSED clauses and balancing

Any form of ENCLOSED-clause (3.2.4) may stand as a primary. Often, the effect is straightforward:

$$ (E1) \qquad y := x \times (a+b) $$

However, let us consider again the example E9 from 3.2.4.1:

(E2) **begin**

`print(4 * (real w := 0, int i := 1; real z = sqrt(small real/2));`
`loop: w := w + 2/(i * (i + 2)); i := i + 4;`
`if 1/i > z then loop fi;`
`w ) )`

**end**

In this example, the value of the serial-clause within the parentheses is, a priori, the name *w* (of mode **ref real**) which will have vanished by the time we are outside the clause. Fortunately it is also clear that, if the value of this serial-clause is a name, it ought to have been dereferenced (because the operator "*x*" is expecting a **real**). However, the rules provide that an ENCLOSED-clause cannot be dereferenced (it is not a coercend). Instead, the required mode and the strength of the context are passed on to the unit which is to be yielded, which in this case is the identifier *w*. Therefore, it is *w* that gets dereferenced, right at the last moment before it disappears, and the resultant **real** value is passed on. The following piece of syntax (which is not the complete syntax for a serial-clause) may make this clearer to those who have some familiarity with the Report [R 3.2.1].
SORT: strong; firm; weak; meek; soft.

SORT MOID serial clause:

strong void unit, go on token, SORT MOID serial clause;

declaration, go on token, SORT MOID serial clause;

SORT MOID unit.

The ENCLOSED-clause might well be a conditional-clause:

$$ (E3) \quad x := (i < 0 | -i | i) $$

or it might be a case-clause:

$$ (E4) \quad x := (i | j, k, m, n) $$

In these cases as well, any coercion that might appear to be needed on the ENCLOSED-clause as a whole is instead performed on the unit(s) inside, as the context may permit. Indeed, different coercions may be applied to different internal units;

$$ (E5) \quad x := \mathbf{case} \ i \ \mathbf{in} \ j, k, x, y \ \mathbf{esac} $$

The first two alternatives in E5 would have to be widened — the last two are already real. Widening is possible because the case-clause occurs in a strong context. However, even if the context had been firm, widening would have been permitted provided that at least one of the alternatives had been real, e.g.:

$$ (E6) \quad a := x \times (i < 0 | j | y) $$

The fact that $y$ is real shows that the version of the operator “$x$” requiring a real is intended, and therefore the context of $j$ can be promoted to strong. The same holds for

$$ (E7) \quad a := x \times (i < 0 | x | k) $$

This principle is known as “balancing”. However:

$$ (E8) \quad a := x \times (i < 0 | j | k) $$

involves the multiplication of a real with an int, and is not balanced.

Balancing is permitted between:

a) The completion points of a serial-clause [R3.2.1] (i.e. the exits and the final unit (3.1.4)), e.g.
$$
\begin{align*}
\text{(E9)} \quad a &:= b + \left( \begin{array}{@{}l@{}} \text{real } x, y, z; z := 1 - 3 \times \sqrt{\text{small real}}; x := i; \\ \quad \text{if } x \le 0 \text{ then go to } \text{libl fi}; \end{array} \right. \\
\text{lobl:} \quad &y := i/x \uparrow 2; x := (2 \times x + y)/3; \\
&\quad \text{if } y/x < z \text{ then go to } \text{lobl fi}; \\
&\quad \text{if } x \ge 10.0 \text{ then go to } \text{libl fi}; \\
&\quad x \text{ exit} \\
\text{libl:} \quad &\text{print ("out of range");} \\
&\quad 10
\end{align*}
$$

Please compare that carefully with 3.1.4. E7.

b) The alternatives of a conditional-clause [R 3.4.1], following then or else (3.2.4.2 and examples E6 and E7 above).

c) The alternatives of a case-clause, including the out option (3.2.4.3), e.g.:

$$
(E10) \quad a := y \times (i \mid j, k, x, y)
$$

d) The alternatives of a 'conformity-clause, including the out option (3.6).

e) The LHS and RHS of an identity-relation (5.7.4). Experienced readers
might like to consider the rather delicate example 5.7.4. E28.
See also 5.5.1.3 for the balancing of transient names.

5.2.0.2. Deproceduring

Deproceduring is a method of calling routines not having parameters, and
has already been introduced in 4.2.2.2. We think it best, however, to consider
it alongside calls of routines which do have parameters, which brings us to:

5.2.1. Primaries — procedure calls

It will have been seen (1.2.3.1 and 4.2) that procedures are declared in
much the same way as other objects, and that they yield values (i.e. their
routines). Thus proc void, proc real, ref proc (int, real) int are perfectly valid
modes. The consequence of which is that if random (which is declared to be
of mode proc real (see 6.2.2)) appears as a coercend, it is not immediately
apparent whether its value (i.e. its routine, which is of mode proc real) is to
be yielded, or whether the intention is to elaborate the routine and to yield
its real result (although the latter may well be intended 99% of the time, the
former facility is needed whenever a procedure is to be assigned, or operated
upon in a formula, or yielded by another procedure – all of these things
being quite allowable).

The distinction between these two interpretations can only be made by
context. There are two cases:

a) Calls [R 5.4.3]

(E11) proc (real) real p; proc sinh = (real x) real: (exp(x) - exp(-x))/2;
y := sinh(x);

(E12) p := sinh

sinh has been declared to be a procedure requiring a parameter. Therefore, in E11 where an actual-parameter is indeed present, the intention is clearly that the procedure should be called. If there are no parameters, as in E12, then its body must be yielded. Thus the problem does not arise.

b) Deproceduring [R 6.3]

proc real q; proc sinh x = real: (exp(x) - exp(-x))/2;

(E13) y := sinh x;

(E14) q := sinh x

sinh x does not require parameters. Therefore, we must see which mode is required by the context. In E13, real is required, which is what the routine yielded by sinh x returns. Therefore we must employ the coercion known as "deproceduring".

The effect of deproceduring is always to convert the mode of a coercend of proc amode into amode (including proc void into void), at the same time calling the value (i.e. the routine) that the coercend yields.

In E14, on the other hand, the mode required is proc real and so the routine yielded by sinh x is assigned without any coercion.

Deproceduring can be used in any context*, including the LHS of an assignation.

In elaborating a call of either sort, it is first necessary to establish what is to be called. In case (a) this is specified by a meek primary yielding the required routine, and the primary is followed by the actual-parameters. The interpretation of these has already been described in 4.2.2.2. Usually, the primary will be an identifier, as ncos (see Appendix 2) in:

(E15) x := ncos (i)

<footnote>* In strong void contexts, there may be some doubt as to whether deproceduring or voiding (5.7.0.1) is to be used. The coercion chart (5.1.0.2) shows that deproceduring is always to be preferred to voiding, except where the coercend is an assignation or a cast. In E14 it was an assignation yielding (a priori) the ref proc real value q. Clearly, to have now called this would have been ridiculous, and therefore immediate voiding was appropriate. If q had stood as an applied-identifier on its own, however, it would have been dereferenced, then deprocedured (so that any side effects of sinh x could happen), and finally voided.</footnote>
However, it could be an ENCLOSED- (e.g. conditional-(3.2.4.2)) clause, as in:

$$ (E16) \quad x := (p | ncos | nsin) (i) $$

In case (b), where deproceduring is to be used, the required routine must be yielded by a suitable unit (but not an assignation or a cast). Again, usually, it will be an identifier as in:

$$ x := random $$

It cannot, however, be an ENCLOSED-clause (which is not a coercend). If *proca* and *procb* are both of mode *proc real*, then:

$$ (E17) \quad x := (p | proca | procb) $$

is legitimate, but the deproceduring of *proca* and *procb* takes place in situ, as you have already seen in 5.2.0.1, and the conditional-clause as a whole yields *real* without further coercion.

The corresponding situation in the case of calls with actual-parameters arises in:

$$ (E18) \quad x := (p | ncos(i) | nsin(i)) $$

which should be compared with example E16 in which the actual-parameter (i) appeared only once.

The modes yielded by the actual-parameters in a call must, of course, match those of the formal-parameters (4.2.2.2) of the routine. However, the context of an actual-parameter is strong, so that all the coercions are available.

### 5.2.3. Tertiaries – nil

nil is a special tertiary of mode *ref amode* which yields a name which does not refer to any value. See 5.2.4.E27 for an example. Note that *nil* is never subject to coercion and that it may only occur where the context is strong.

### 5.2.4. Quaternaries – assignations involving names

Here are some examples of assignations involving names. Remember that *xx* and *yy* are of mode *ref ref real* and that *a*, *x* and *y* are merely *ref real*:

$$ (E19) \quad xx := \text{if } i<0 \text{ then } x \text{ else } y \text{ fi}; $$

The value of *xx* is therefore the name *x* or the name *y*.
(E20) $yy := xx;$

and so is the value of $yy$.

(E21) $a := xx;$

The value currently referred to by $x$ or $y$ (whichever was assigned to $xx$) is assigned to $a$. Note that $xx$ is dereferenced twice in this example.

(E22) `ref real (xx) := a;`

The value referred to by $a$ is assigned to $x$ or to $y$. $xx$ is here put in a cast, so that it may be dereferenced. There is normally little point in using a cast as the RHS of an assignment, since:

(E23) $y := \text{real}(x);$

means the same as:

(E24) $y := x;$

(E25) $a := xx := x;$

means the same as $a := \text{real}(xx := x)$, in which the name $x$ is assigned to $xx$, the value referred to by the value referred to by which (i.e. it is dereferenced twice) being then assigned to $a$. On the other hand:

(E26) $xx := a := x;$

means the same as $xx := (a := x)$, in which the value referred to by $x$ is first assigned to $a$, and the name $a$ is then assigned to $xx$ (but the resultant value of $xx$ is no way dependent upon $x$, so that one might just as well have written $a := x; xx := a$).

(E27) $xx := \text{nil}$

means that the value referred to by $xx$ is a name which does not refer to anything.

Vertical readers, please turn to 6.2.
## 5.4. Units and structures

### 5.4.0. Coercion — complex widening

The widening of ints into reals was introduced in 5.1.0.4. In a similar fashion, it is possible to widen a real into a compl, provided the context is strong. Thus:

$$ (E1) \qquad z := x $$

x is first dereferenced into a real and then widened.

$$ (E2) \qquad z := 2 $$

Here the int 2 is first widened into a real, and then widened again into compl.

Even an implementation (of a sublanguage) which does not include the compl operators in its standard-prelude ought to implement this particular widening (i.e. of a struct (real re, im)), in order that a user may then declare these operators himself, and use them in the normal fashion.

### 5.4.1. Primaries — applied identifiers

Clearly, once a struct (or a ref struct, etc.) has been ascribed to an identifier, then that identifier can stand as a unit, and the value yielded is the whole of some structure (however complicated) of the appropriate mode (or the name of such a structure). For example, in:

$$ (E3) \qquad v1 := v2 $$

v2, which is of mode ref struct (real xcoord, ycoord, zcoord) (see Appendix 2) is dereferenced to yield a value (consisting of three real quantities) which is of mode struct (real xcoord, ycoord, zcoord). Such identifiers can occur in assignments (as above), or in formulas, as in:

$$ (E4) \qquad v1 := v2 + v3 $$

or in selections, as will now be discussed.

### 5.4.2. Secondaries — selections

A 'selection' is a form of secondary which can be used to obtain an individual field out of a structure, thus:

$$ (E5) \qquad xcoord of v1; re of z $$

Here, xcoord and re are field-selectors (see 2.4.1) and v1 and z are identifiers.
More specifically, any weak secondary can be selected from, and this has various consequences as follows:

a) Because it is weak, the secondary can be dereferenced, but a special provision attaches to weak dereferencing. If we have a name referring to a structure, we have the right to expect, from our selection, a name referring to the selected field, and so the dereferencing of the secondary must yield the name of the structure, never the structure itself. Therefore, in weak dereferencing, succeeding *refs* may be removed from the mode of the secondary until one remains, but this last one cannot go.

A special rule now provides that where the secondary thus yields the name of a structure, the selection as a whole yields the subname (1.1.4.2) referring to the selected field (but if the secondary (being of a non-ref mode) yields the structure itself, then the selection yields the field itself). For example in:

(E6) `xcoord of v1`

`v1` is of mode `ref struct (real xcoord, ycoord, zcoord)` and hence the example as a whole yields a name of mode `ref real`. This selection as a whole may now be dereferenced if its context is strong, firm or meek, as happens in:

(E7) `x := y + xcoord of v1`

However, if we declare:

(E8) `vec w1 = (1, 2, 3);`

in which `w1` is of mode `vec`, then:

(E9) `xcoord of w1`

is of mode `real`. Thus both `v1` and `xcoord of v1` are acceptable on the LHS of an assignation, but `w1` and `xcoord of w1` are not.

For another viewpoint over this whole matter, you are invited to re-read 1.4.3.

b) Because it is a secondary from which the selection is made, and because a selection is a secondary, it follows that selections can be selected from. If we declare:

(E10) `mode tens = struct / vec xlevel, ylevel, zlevel); tens u1;`

then we may call upon:

(E11) `xcoord of ylevel of u1`

and the result is of mode `ref real`. Moreover, if we declare:
(E12) mode man = struct('int age', ref man father); man jones;

then we may call upon:

(E13) age of father of father of father of father of jones

and the result is of mode ref int. Each time we select a father in this example, we obtain a ref ref man which, since it occurs in a weak position, can be dereferenced as far as ref man which is just what we need in order to be able to select another ref ref man from it.

### 5.4.3. Tertiaries — formulas with complex operators

It will be recalled (2.4.4) that compl is really a structure of mode struct (real re, im). Six special operators are provided for use with compls. They are re, im, abs, arg, conj and i. The first four operate on compl and yield real. For example:

(E14) re z means the same as real (re of z)

(E15) re (w + z) means the same as re of (w + z)

(E16) abs z means the same as sqrt (re z↑2 + im z↑2)

Contrariwise:

(E17) re w := x

is not permitted, although:

(E18) re of w := x

is.

(E19) conj z means the same as re z i - im z

i is a dyadic-operator which produces a compl out of two reals or ints.

Thus:

(E20) z := x i y means the same as z := (x, y)

However:

$$z := w + (x, y)$$

is not legitimate because the context of (x, y) is not strong.

(E21) z := w + x i y
is all right because i is of higher priority than "+".

N.B. Those still unhappy with the interpretation of $-x↑2$ should pay some attention to re $z↑2$, in E16 above.

**Vertical readers**, please turn to 7.4.

## 5.5. Units and multiples

### 5.5.0. Coercion - rowing

The restriction that a row-display (3.5.1) should contain either zero or at least two units is necessary in order to avoid ambiguity. However, a multiple value is perfectly entitled to contain only one element, and in order to be able to assign values to such multiples a coercion known as "rowing" is provided. This may be used in any strong context. Thus, given:

(E1) **flex** [1 : 2] real w1;

then

(E2) $w1 := 2.4$;

causes a multiple (with bounds [1 : 1]) of one element (i.e. 2.4) to be assigned to w1. Also:

(E3) $w1 := (1, 2, 3)$;

**flex** [1 : 2, 1 : 4] real w2 := w1;

gives w2 the bounds [1 : 1, 1 : 3].

Likewise:

(E4) **flex** [1 : 2] [1 : 3] real w3 := w1;

gives w3 the bounds [1 : 1] [1 : 3].

Thus, rowing consists of adding one 'row' or one 'row of' to the mode of a value, at the same time providing bounds [1 : 1] (several 'row's or 'row of's may be added by repeated rowing). See also 5.5.1.3. E20 for how to produce names by rowing

### 5.5.1. Primaries

#### 5.5.1.1. String denotations

A **string** is of course of mode [ ] `char`, and therefore a literal string could
be provided by means of a row-display:

(E5) $s := ("T", "H", "E", "\_", "Q", "U", "I", "C", "K")$

However, a more compact denotation is provided:

(E6) $s := "THE.QUICK.BROWN.FOX.JUMPS.OVER.THE.LAZY.DOG"$

The value of the RHS here is a multiple value of mode *string*, and with bounds [1:43]. Note the denotation "\_" for the space character. You can, if you like, use a space as the space-character:

(E6*) $s := "BUT IF YOU HAVE A VERY LONG STRING-DENOTATION WHICH CONTINUES ON TO THE NEXT LINE, HOW CAN YOU TELL HOW MANY SPACES THERE WERE AT THE LINE BREAK?"$

Presumably as many as you actually punched when you punched the program in the first place. Note that this is an exception to the general rule (1.3.2) that blank spaces have no meaning in this language.

If the quote-sumbol itself is required to appear in the string, it must be represented by two quote-symbols (i.e. ""), thus:

(E7) $s := "He said ""she said ""he is a liar""""$

An empty string can also be assigned:

(E8) $s := ""$

There is no denotation for a string of one character only. However, in strong positions the same result can be obtained by taking a character-denotation (5.1.1.1) and rowing (5.5.0) it:

(E9) $s := "A"; s := """"$

Note that a comment may not appear inside a string- (or character-) denotation, and thus the comment symbol (\*) may safely appear, and stand for itself [R 8.1.4.1].

### 5.5.1.2. Applied identifiers

Clearly, once a multiple (or a *ref* to a multiple, etc.) has been ascribed to an identifier, then that identifier can stand as a unit, and the value yielded is the whole of some multiple value of the appropriate mode (or the name of such a value). Note that the value so yielded includes a descriptor. For
example:

$$ (E10) \quad x1 := y1 $$

(in which $y1$ has to be dereferenced before a multiple value is obtained).

### 5.5.1.3. Shices

Slices are used in order to dissect multiple values. They consist of a weak primary, which yields a multiple value, followed by an 'indexer' containing a series of 'trimscripts' which specify which parts of that multiple value are required. Trimscripts may be either 'subscripts' or 'trimmers'.

Let us declare:

(E11) [,,] real x3 = (c some multiple with bounds [0:l-1, 0:m-1, 0:n-1] c);

which is of mode [,,] real. It can be represented thus:

<figure><img src="image_81.png" /></figure>

ABCDEF GH represents the whole value, x3. From this, we may select the plane PQRS by writing:

$$ (E12) \quad x3[i,,] $$

which yields a value of mode [,,] real. This could now be assigned to any doubly subscripted variable which it happened to fit. Here, *i* is a subscript. Further subscripts can be used to yield the row JM (of mode [] real) and the element W (of mode real):
(E13) $x3[i,j1,] ; x3[i,j1,k1]$

To obtain the column TN (of mode [ ] real) we write:

(E14) $x3[i, , k1]$

Trimmers are used to obtain a part (a "subvalue") of a row, column, etc. The required lower- and upper-bounds (both inclusive) are given, separated by a colon. Additionally, the 'revised-lower-bound' from which the yielded bounds are to run is also specified following an @ (effectively, the subvalue between the specified lower- and upper-bounds is extracted, and its bounds are then "slid down" until the revised-lower-bound is reached). If no revised-lower-bound is specified, @1 is assumed. The following examples should make this clear:

<table><thead><tr><th>slice</th><th>value yielded</th><th>mode yielded</th><th>bounds yielded</th></tr></thead><tbody><tr><td>(E15) x3[i, j1:j2@j1, ]</td><td>JKLM</td><td>[, ] real</td><td>[j1:j2, 0:n-1]</td></tr><tr><td>x3[i, j1:j2, ]</td><td>JKLM</td><td>[, ] real</td><td>[1:j2-j1+1, 0:n-1]</td></tr><tr><td>x3[i, :j1, ]</td><td>PJMS</td><td>[, ] real</td><td>[1:j1+1, 0:n-1]</td></tr><tr><td>x3[i, :]</td><td>PQRS</td><td>[, ] real</td><td>[1:m, 0:n-1]</td></tr><tr><td>x3[i, j2: @j2, ]</td><td>KQRL</td><td>[, ] real</td><td>[j2:m-1, 0:n-1]</td></tr><tr><td>x3[i, k1:k2]</td><td>NTUV</td><td>[, ] real</td><td>[0:m-1, 1:k2-k1+1]</td></tr><tr><td>x3[i,j1:j2@j1, k1:k2@k1]</td><td>WXYZ</td><td>[, ] real</td><td>[j1:j2, k1:k2]</td></tr><tr><td>x3[i, j1, k1:k2]</td><td>WZ</td><td>[ ] real</td><td>[1:k2-k1+1]</td></tr><tr><td>x3[i,j1:j2, k1]</td><td>WX</td><td>[ ] real</td><td>[1:j2-j1+1]</td></tr><tr><td>x3[i, j1, k1]</td><td>W</td><td>real</td><td>-</td></tr><tr><td>x3[,, ]</td><td>ABCDEFCH</td><td>[,, ] real</td><td>[0:l-1, 0:m-1, 0:n-1]</td></tr><tr><td>x3[::, ::, ::]</td><td>ABCDEFCH</td><td>[,, ] real</td><td>[1:l, 1:m, 1:n]</td></tr><tr><td>x3</td><td>ABCDEFCH</td><td>[,, ] real</td><td>[0:l-1, 0:m-1, 0:n-1]</td></tr></tbody></table>

(The last line is not strictly a slice at all).

Note that, if a bound is omitted from a trimmer, the bound currently existing in that multiple is implied. Moreover, if both bounds are omitted, both existing bounds are taken (but @1 is still implied). Alternatively, when both bounds are absent, the colon may be omitted as well, but now the existing lower-bound is assumed (i.e. there is no sliding). This accounts for the difference between $x3[,, ]$ and $x3[::, ::, ::]$ in E15. The first is the same as $x3$ (no trimmers, existing bounds). The second is an abbreviation for $x3[0:l-1, 0:m-1, 0:n-1]$ (full set of trimmers, with @1 implied for each).

Subscripts, and bounds occurring in trimmers, are meek int units, and therefore expressions of considerable complexity can be used, including any coercion that is able to yield int. The use of an assignation will be quite common:
$$ (E16) \quad x3[j := i, ] $$

A slice consists of a weak primary, followed by an indexer. The weak primary leads to the following consequences:

a) Because it is weak, it can be dereferenced, but only until one ref is left (see 5.4.2 for the corresponding phenomenon in connection with selections). Thus dereferencing can never yield the multiple value itself.

A special rule now provides that where the primary thus yields the name of a multiple value, the slice yields the subname which refers to the element or subvalue that has been sliced (but if the primary already yields a multiple value — as x3 in the examples above — then the slice yields the element or subvalue itself). The similarity between this and the corresponding provisions for selections (5.4.2) should be noted.

However, names referring to multiple values may be either fixed or flexible (2.5.2.1) so that there are two cases to consider. For example, in:

$$ (E17) \quad x1[i] $$

x1 is a fixed name of mode ref [] real, and hence the example as a whole yields a name of mode ref real, which may itself now be dereferenced if its context is strong, firm or meek, as happens in:

$$ (E18) \quad x := y + x1[i] $$

whereas in:

$$ (E19) \quad xx := x1[i] $$

we have obtained, in xx, a pointer to a real value, which just happens to be a particular element of a [] real.

(The converse operation, in which a pointer intended for a multiple value can instead point to a single value is also possible:

$$ (E20) \quad ref [] real xx1 := x; $$

This involves rowing (5.5.0), and the bounds, when the real value referred to is accessed via xx1, are [1:1].

A pointer to a subvalue can also be obtained:

$$ (E21) \quad ref [] real xx1 := x2[2:4, i]; $$

in which xx1 is made to point to part of the i'th column of x2.

If, however, the primary yields a flexible name, as in:

$$ (E22) \quad al[i] $$

where al is of mode ref flex [] real, we have to be careful. We indeed get a
name, and its mode is **ref real** as in E17, but it is said to be a "transient name" [R 2.1.3.6.c] because it is only meaningful so long as the flexible *al* stays the same size. If the whole of *al* is subsequently assigned to, it may grow or contract and, in the process, be re-incarnated at a different address in the store. What happens now if a subname referring to an element or subvalue in the old store address has been preserved somewhere?

Clearly, transient names are undesirable things to hang on to, and it is therefore forbidden for them to be either assigned, or ascribed, or passed to or returned by a routine. They may be dereferenced, or stand on the LHS of assignments, so that we may have

$$ (E23) \quad x := y + a1[i]; a1[2:5] := (a, b, x, y); $$

but not

$$ (***) \quad xx := a1[i] \quad \& \quad \text{cf. E19 \&} $$

Care must therefore be taken, when using the **flex** feature (and especially the mode **string**), to avoid these situations. Indeed, these unfortunate, but necessary, restrictions are a significant limitation on the usefulness of flexibility.

(Transient names can also arise in rowing, with the same restriction. Thus we may have

(E24) [1:1, 1:4] real b2;
($p$ | $b2$ | $a1$) := [] real $(a, b, x, y)$ & $a1$ is rowed to ref [] real $\&$

but not

$$ (***) \text{ref } [, ] \text{ real } xx2 := a1; \& \text{cf. E20 \&} $$

nor even

$$ (***) \text{ref flex } [, ] \text{ real } xx2 := a1; $$

Note how E24 illustrates the balancing of a fixed name (*b2*) against a transient name (the rowing of *al*) to give a transient name.)

b) Because it is a primary, it follows that any suitable ENCLOSED-clause can be used, thus:

$$ (E25) \quad \text{if } i < j \text{ then } x1 \text{ else } y1 \text{ fi } [2 : n-1] $$

Even a **string** denotation can be trimscripted:

$$ (E26) \quad \text{"abcd" } [2] $$

yields "b". However, a row-display cannot be used because its context must
be strong, not weak (3.5.1). However, it can always be cast:

(E27) $[\int j, k, l, m][i]$

Of course, slices can always be sliced again:

(E28) $w3[i][j] \quad \text{see 5.5.0.E4}$

c) Because a selection is a secondary, parentheses may be needed when slices and selections are to be combined:

(E29) $p$ of $q[i]$

is only meaningful if $q$ is of some mode such as $[\text{struct/amode } p, ...]$, in which case the $i$th structure is to be sliced from the multiple, and then the field $p$ is to be selected from it.

(E30) $(p \text{ of } q)$ [i]

is only meaningful if $q$ is of some mode such as $\text{struct/}[\text{amode } p, ...]$, in which case the field $p$ (which is a multiple) is to be selected from the structure $q$, and the $i$th element is to be sliced from it. See 1.4. E13 for a similar case concerning a selection which yields a procedure.

### 5.5.2. Secondaries — multiple selections

Suppose we have a row of structured values (e.g. complex numbers). We may select a row of fields:

(E31) $x1 := re \text{ of } z1$;
$\text{ref } [\text{ real } xx1 := im \text{ of } z1}$

Observe that $(re \text{ of } z1)[i]$ and $re \text{ of } (z1[i])$ therefore both select the same **real** value, but by completely different mechanisms!

Again, the possibility of transient names arises, so preventing

(***) $\text{flex } [1:n] \text{ compl' } c1$;
$\text{ref } [\text{ real } xx1 := re \text{ of } c1]$

### 5.5.3. Tertiaries — bound interrogations

It is useful to be able to discover the actual value of the bounds of a multiple which is on hand, particularly so when it is a formal-parameter of a routine, and the bounds of the actual-paramter are needed inside the routine. Two special operators are provided for this purpose:
$$ (E32) \quad \begin{array}{l} n \text{ lwb } x3; \\ n \text{ upb } x3 \end{array} $$

These two formulas yield, respectively, the lower- and upper-bounds of the nth boundpair (see 1.5.1) of the multiple x3. (For example, with x3 declared as in E11, 3 upb x3 would yield the value $n - 1$).

For getting at the first (or only) boundpair, monadic versions of lwb and upb are provided. Thus:

$$ (E33) \quad \text{upb } x1 $$

means the same as

$$ (E34) \quad 1 \text{ upb } x1 $$

All these operators are introduced formally in 6.5.

### 5.5.4. Quaternaries – assignations

There are three questions to be answered:

1) What happens when the LHS yields a flexible name (2.5.2.1)?

2) What happens when the LHS is a slice?

(Note that these two questions can never arise together, because a slice cannot yield a flexible name).

3) What happens when the LHS and the RHS involve the same multiple value?

#### 5.5.4.1. Flexible assignations

In the first place, it must be stated that the bounds on the two sides of an assignation must match exactly. Thus:

(***) \[1:3] real $xa$, \[2:4] real $xb$; $xa := xb$

can never be legitimate under any circumstances.

However, if the LHS yields a flexible name (and this can only occur when the whole of some multiple is being assigned to), then the bounds from the RHS are copied across. This means that a flexible multiple may well change its size when the whole of it is assigned to. Given the declaration:

(E35) flex \[1:0] real $c1$, \[0:n-1] real $d1$;

(E36) $c1 := d1$
causes `c1` to acquire the bounds `[0:n-1]`, whereas:

(E37) $c1 := d1[2:n-2]$

causes `c1` to acquire the bounds `[1:n-3]`.

### 5.5.4.2 Assignation to slices

When the LHS of an assignation is a slice, then of course only the sliced part of the multiple referred to is assigned to. First, however, the bounds of the slice are elaborated, and slid down according to any `@s` that may be present. These bounds are then compared with those on the RHS to see whether the assignation is legitimate. If it is, the value of the RHS is assigned to the slice on the left (but as selected by the un-slid bounds, of course). Thus, given the declarations:

(E38) `[1:3] real xa, [2:4] real xb, [1:2] real xc, [2:3] real xd;`

the following statements are all legitimate:

(E39)
* `xa [2:3] := xc;`
* `xa [2:3 @ 2] := xd;`
* `xa [2:3] := xd[@1];`
* `xa[@1] := xb[@1]`
* `xa[:] := xb[:]`

In these examples the bounds used for comparison purposes are `[1:2]`, `[2:3]`, `[1:2]`, `[1:3]` and `[1:3]` respectively, but in all of the first three cases it is `[2:3]` of `xa` that get altered. The fourth and fifth cases show how the presumably intended effect of `xa := xb` (which is not legitimate) can be achieved.

### 5.5.4.3. Overlapping slices

Suppose we wish to effect a cyclic permutation of the elements of `x1`. Then we may write:

(E40)
* `y1[2:n] := x1[1:n-1];`
* `y1[1] := x1[n];`
* `x1 := y1`

However, we might consider the effect of:
$$
\begin{align*}
\text{(E41)} \quad & x := xI[n]; \\
& xI[2:n] := xI[1:n-1]; \\
& xI[1] := x
\end{align*}
$$

Consider the second line of this:

$$
x1[2:n] := x1[1:n-1];
$$

in which the slice being assigned from overlaps the slice being assigned to.
Does this work, or is it equivalent to:

$$
\text{for } i \text{ from } 2 \text{ to } n \text{ do } x1[i] := x1[i-1] \text{ od;}
$$

(which has rather a disastrous effect)? Fortunately, the overlapping slices of
E41 do work correctly, and it is up to the implementation to ensure that it
starts the copying operation at the correct end.

Vertical readers, please turn to 6.5.
## 5.6. Units and unions

(E1) union / int, real) ira, irb;

ira and irb may refer to values of mode either **int** or **real**. However, this raises no problem when one is assigned to the other:

(E2) ira := irb;

since ira now refers to whichever mode irb referred to before. The modes on the two sides of E2 are both **ref union** / **int**, **real**), and the RHS is dereferenced as usual.

The problems do not begin to arise until we want to set the mode of irb in the first place (by assigning an **int** to it, for example) or until we want to get an **int** out of it again (always assuming that it happens to refer to an **int** at the time in question). The first of these problems is dealt with by a new coercion known as "uniting". The solution to the second has already been given in 3.6 (conformity-clauses).

### 5.6.0. Coercion - uniting

It should be emphasised that there are no built-in-operators for operating on **unions** so *ira* + *irb* is not a valid formula unless you have suitably defined "+" for yourself. This is reasonable because your compiler could not tell whether you were trying to add a **real** to an **int** or an **int** to an **int** or whatever. Therefore, all arithmetic must be done on ununited operands. Once you have a value of some definite mode, however, (and if your context is at least firm) then you may unite it to yield any **union** containing that mode which may be demanded by the context:

(E3) ira := i+2;

Here, *i+2* is of mode **int**. The mode required is **union** / **int**, **real**) and the context is strong (being the RHS of an assignation). Therefore *i+2* is united to be of mode **union** / **int**, **real**) and as such it can now be assigned to *ira*. Because the uniting was from an **int**, *ira* now refers to an **int** value. You might be tempted to think that this example is ambiguous, because the *i+2* might also be widened to **real** and then united. However, if you try to follow through this possibility on the coercion chart given in 5.1.0.2, then you will find that it has been carefully excluded — the only coercions that may precede uniting are the meek ones.

(E4) union (bool, int, real) bira;

bira := ira;
Here, *ira* is united from union (int, real) into union (bool, int, real). This is quite in order because all the constituent modes of the former are also constituents of the latter.

### 5.6.1 Primaries — the void denotation

One of the few places where void values are actually useful is in unions such as

(E5) union (real, int, void) *riv*;

Here, *riv* may refer to a real value, an *int* value, or to no value at all (i.e. a void value). We can bring about the last state of affairs using the void denotation empty:

(E6) *riv* := empty;

and of course we can test for this case in a conformity-clause:

(E7) case *riv* in (real *x*): print(*x*),
       (int *i*): print(*i*),
       (void): print("neither")
    esac

### 5.6.4. Quaternaries — assignations of unions of rows

Multiple values inside **unions** are always declared with formal bounds (2.5.2.3) [R 4.6.1.u]:

(E8) union ( [ ] int, [ ] real, bool) *irla*;

The effect is much as if the bounds had been preceded by *flex*, insofar as a multiple value of any size (and suitable mode) may be assigned thereto:

(E9)
*irla* := y1;
*irla* := i1 [17:23];
*irla* := i1

In all these examples, the RHS is united before being assigned. The whole of the multiple value on the RHS (bounds and all) is copied across regardless [R 5.2.1.2.b]. There is no question of checking the existing bounds of the LHS (for if *irla* had previously referred to a *bool*, there would have been none).

A union containing multiples cannot be sliced (5.5.1.3), so there is no question of assigning to only a part of it. To get at a part of its existing value, we use a conformity-clause (3.6):
(E10) `il [17:23] := (irla | ([] int ij1): ij1)[17:23]`

Note that if `irla` did not refer to a `[] int` at this time, the result of E10 would be undefined.

It is, however, possible to discover the bounds of the multiple within a **union** without all this bother, provided the **union** consists of multiples and nothing else [R 10.2.3.1.a]. Thus `irla` as declared in E8 would not do, but if we declare:

(E11) `union ([] int, [, ] real/ir1b;`

then we can say:

(E12) `i := lwb ir1b;` `‡` yields the lower-bound of the first or only boundpair `‡`

`p := 2 upb ir1b` `‡` yields the second upper-bound, so that it is undefined unless `ir1b` is currently exercising its `[] real` option `‡`

Vertical readers, please turn to 7.6.
## 5.7. Bits and pieces of garbage

### 5.7.0. Coercion

#### 5.7.0.1. Voiding

We have one coercion left to consider, although we have in fact been using it informally all along. Formally, it is necessary in order to satisfy the general syntactic rule that the mode of each external object must, a posteriori, be that required by its context.

The bulk of any ALGOL 68 program will consist of statements forming the bodies of serial-clauses (3.1.2). Statements are, of course, void-units, but in practice most of them will be assignations which yield a value (the name yielded by the LHS). This value is thrown away by "voiding" [R 6.7]:

(E1) `begin x := 1; y := 2; z := 3 end`

The first two assignations in this will certainly be voided. Whether the third one is or not depends upon whether the context in which the whole closed-clause occurs expects `void`.

Voiding can occur in strong contexts (but all contexts where `void` is required are strong anyway) and may in most cases be preceded by deproceduring (see coercion chart in 5.1.0.2):

(E2) `...; x or y; $\ddagger$` see Appendix 2. `x or y` is deprocedured and the next random number is taken but (the context requiring `void`) its real result is then thrown away by voiding $\ddagger$

However, an assignation (or a cast) must never be deprocedured and then voided, for otherwise in:

(E3) `proc void ppp; ppp := finish;`

we should have to assign `finish` to `ppp` and then, by deproceduring the whole assignation, call the routine now referred to by `ppp` (i.e. `finish`). The assignation is therefore voided straight away.

It is useful to note that the context immediately preceding a ";" is always `void` (and strong).

#### 5.7.0.2. bits and bytes widening

In strong contexts, `bits` values can be widened to `[] bool` and `bytes` values to `string`. The bounds of the `[] bool` will always be `[1: bits width]` (see
6.2.1) and the string will always contain exactly *bytes width* chars.

Here is an example in which a slice is trimmed out of a *bits* value. Note the use of a cast to give strength to what would otherwise have been a weak context (5.5.1.3):

(E4) `bits t := 2r1011100;` `‡` for *bits* denotations see next section `‡`
`[1:3] bool b1 := [ ] bool (t) [bits width-4: bits width-2];`
`‡` yields (`true`, `true`, `true`) `‡`

Similarly, *longs* and *shorts bits* and *bytes* can be widened, the upper-bound of the resultant value being given by environment enquiries such as *short bits width*, *long long bytes width*, etc.

### 5.7.1. Primaries

#### 5.7.1.1. *bits* denotations

A special form of denotation [R 8.2] is provided for values of mode *bits*:

(E5) `bits bits := 2r101101011001;`

which means that the value assigned to *bits* is the row-display:

(false ... false, true, false, true, true, false, true, false,
true, true, false, false, true)

Note that the correct number of *falses* is automatically inserted at the left hand end. The *2r* means that the *bits* denotation is in binary. Radices *4, 8* and *16* are also possible:

(E6)
*   `4r231121`
*   `8r5531`
*   `16rb59`

These all yield the same value as that in E5. Note the use of the letters *a-f* to denote the "digits" 10-15.

Thus if you like quoting your *ints* in octal, you can always write:

(E7) `i := abs 8r12` `‡` meaning `i := 10 ‡`

(For the operator *abs*, see 6.1.1).

#### 5.7.1.2. *long* and *short* denotations

There is no coercion provided in the language for converting a *real* into a
**long real** or a long long real. Therefore the a priori mode of any object must already contain the right number of **longs**. In the case of denotations (**int**, **real** and **bits**) this is achieved as follows [R 8.1.0.1]:

(E8) `long int iiiint := long 12233344455555; short int it := short 12;`
`long long real reaeal := long long 3.1415926535 8979323846;`
`long long long bits biiiits := long long long`
`2r1011001011010111000101100101100101101101011;`

There are no long forms of **bool**, **char**, or **string** denotations.

### 5.7.2. Secondaries – generators

**'Generators'** [R 5.2.3] are used to make available to the user regions of store where values may be put. They yield the names of those regions. A generator consists of an actual-declarer (2.1.2 and 2.5.2.2), preceded by **loc** or **heap**.

#### 5.7.2.1. loc generators

In the case of **loc** generators, the scope (3.2.2) of the name thus created is the lifetime of the "local range" in which the generator appears. The "local range" is the smallest enclosing range (3.2.1) containing the generator which is either

a) a routine-text, or

b) a serial-clause with at least one declaration (3.1.1), except that
   priority-declarations (4.3.1) do not count, or

c) an enquiry-clause together with the remainder of its choice-clause
   (3.2.4.2, 3.2.4.3, 3.6) or loop-clause (3.5.2), if that enquiry-clause
   contains at least one declaration (priority-declarations again excepted).

(E9) `begin`
   `[I:n] ref real xx1;`
   `for i to n`
   `do xx1[i] := case sign i1[i] +2 in x1[i],`
   `       nil,`
   `       loc real := 0forc`
   `       od;`
   `comment` At this point, each element of the multiple value
   `xx1` has been set up referring to either an element of `x1` (if the
   corresponding element of `i1` was negative), or to no value at
all (if zero), or to some value specially created for the purpose by the generator loc real, and initially set to zero. The number of these special values is determined at run time, according to the values of the elements of *il*. The only way to gain access to them, at the moment, is via the elements of *xx1*. Because a loc generator was used, they will all disappear when we leave this range. comment

skip

end

¢ At this point, *xx1* has disappeared, and so have any locally generated values to which it referred ¢

In this example, the generator loc real, each time it was encountered, would reserve storage for one real value (presumably on the same stack as *xx1* and *i*) and yield the name referring to that value. *o* would then be assigned to that name, and the name itself would be assigned to *xx1[i]*.

Although the generator loc real in this example is contained within the range lying between the case and the *esac*,

which is in turn contained within the range lying between the *do* and the *od*,

which is in turn contained within the range lying between the *for* and the *od* (but excluding the *to n*, see 3.5.2),

which is in turn contained within the range lying between the *begin* and the *end*,

only the last range of the four is the local range in question, since the others do not declare anything, neither are they routine-texts.

loc generators are sometimes useful for creating triangular and other oddly-shaped multiples:

(E10)
begin
  flex [1:0] ref flex [] real triangle;
  mode array = flex [1:0] real; ¢ to save ink ¢
  triangle := (loc array := 1,
                loc array := (1,2),
                loc array := (1,2,3),
                loc array := (1,2,3,4));
  for i to 4 do print (triangle [i] [i]) ¢ prints the diagonal ¢
  end
end

Outside the range of E10, both *triangle* and the *arrays* to which it referred will have vanished.
The slice *triangle* [*i*] [*i*] is worthy of further examination. *triangle* itself is of mode **ref flex** [ ] **ref flex** [ ] **real**. *triangle* [*i*] is a slice of mode **ref ref flex** [ ] **real** (for the reasons explained in 5.5.1.3). It yields the name of the name of the *i*th row of *triangle* (it is impossible to get hold of the columns). In order to be able to take a further slice out of *triangle* [*i*], we must demonstrate that it is a weak primary of mode **ref flex** [ ] **real**. Now a slice is a primary (5.1.0.1) and a weak primary of mode **ref flex** [ ] **real** can be obtained by dereferencing a slice of mode **ref ref flex** [ ] **real**, such as *triangle* [*i*], and there we are. We can make the further slice *triangle* [*i*] [*i*], and the mode it yields is **ref real**. In E10 this was then dereferenced once more so that a **real** value could be printed.

Now, we shall remind you for the last time that:

(E11) **real** *x*;

means exactly the same (2.2.2) as:

(E12) **ref** **real** *x* = **loc** **real**;

*x* is here declared to be of mode **ref real** and the name of the piece of store made available by the generator **loc real** has been ascribed to it. Since it is a **loc** generator, the piece of store will cease to be available outside the range in which E11 or E12 appeared. Also, outside this range, the identifier *x* cannot occur (or if it does, it identifies something completely different). Thus *x* and the name which it yields rise and fall together.

### 5.7.2.2. heap generators

In the case of **heap** generators, the scope (3.2.2) of the name that is created is not restricted to the lifetime of any range:

(E13) **begin**
    **real** *w*;
    *w* := 10.5;
    *xx* := **heap real** := *w*⁴ creates an extra instance of 10.5
           on the heap⁴
**end**;

**comment** now we are outside the reach of *w* and of the first instance of 10.5 to which it referred. However, the second instance of 10.5 is still intact, and is accessible via the variable *xx* **comment**

**print** (*xx*);⁴ prints 10.5 (after dereferencing *xx* twice)⁴
`xx := x` `¢` the instance of 10.5 on the heap is now quite inaccessible, because no-one now refers to it `¢`

In this example, when the **heap generator heap real** was encountered, storage for one **real** value was reserved (but not on the main stack such as was used by *w* — thus a different region of store, usually termed the “heap”, is involved). The generator yielded the name referring to this piece of storage, the value 10.5 was assigned to it, and it was assigned to *xx* (which is of mode **ref ref real** — see Appendix 2). Both *xx* and this value remained fully available outside the range in which **heap real** occurred, and were used in the *print*. However, after this, *xx* was used for something else and the 10.5 was just left sitting there.

Thus it is very easy to waste large amounts of the heap:

(E14) to 10000 do heap real od

this will reserve 10,000 words on the heap, and there will be no way of accessing any of them — they will in fact be “garbage”. Therefore it will be necessary for your implementation to include in your run-time program a “garbage collection routine” which will be called in whenever the size of the heap has become embarrassingly large. How this works in detail is your implementor’s worry, but it will go something like this:

1) Consider all the values (on the stack) which are names that have been ascribed or assigned to identifiers (i.e. all identifiers declared with mode **ref ref amode** and some with **ref amode** within the current range, or its surrounding ranges).

2) If any such name refers to a value on the heap, mark that area of the heap as useful (this could be done by a vast array of bits, one for each word on the heap). Since the mode of the name is always known, the size of the value can easily be determined.

3) If the value referred to by any such name contains further names within itself (again, this will be apparent from the known mode of the given name), then consider these names also.

4) Go through the array of bits searching for areas of the heap that have not been marked as useful. These areas can now be made available for further use.

This process will be recognised as being similar to that employed in list-processing languages such as LISP, and it is for applications in which list-processing would otherwise have had to be used that **heap generators** are primarily intended.
You can, if you like, do fairly conventional list-processing in this language:

(E15)
mode atom = union (char, int);
mode cons = struct (union (atom, ref cons) car, ref cons cdr);
proc list = ( [ ] union (atom, ref cons) item) ref cons:
    begin
        ref cons a := nil;
        for i from upb item by -1 to 1
            do a := heap cons := (item [i], a) od;
        a
    end;
ref cons expression := list ("X", "+", list("Y", "x", 2)));

However, if you intend to create many lists with the same layout, it is better
to declare them as structs, and generate them as such:

(E16)
mode operand = union (char, int, ref expression);
mode expression =
    struct ( operand left, char operator, operand right);
ref expression expression := heap expression :=
    ("X", "+", heap expression := ("Y", "x", 2));

This version is more convenient to write, will use less storage space, and will
have its garbage collected more speedily (since a complete expression can be
removed at one go).

As was mentioned in 2.7.3, the declaration:

(E17) heap real x;

means exactly the same as:

(E18) ref real x = heap real;

x is here declared to be of mode ref real and to yield the name of the piece of
store made available by the generator heap real. This piece of store will still
be available outside the range in which E17 or E18 appeared, even though the
identifier x cannot occur there (or if it does, it identifies something
completely different). It could be accessed in the following circumstances,
which should be compared with E13:
(E19)
begin
    heap real w;
    w := 10.5;
    xx := w
end;

print(xx); c prints 10.5 c
xx := x c the instance of 10.5 on the heap is now garbage c

### 5.7.3. Tertiaries — order of elaboration of operands

The elaboration of a dyadic-formula involves the elaboration of two operands (these are either other formulas or secondaries). These two operands are elaborated collaterally (see 3.7.1). The following dangerous example illustrates this, and should be compared with 3.7.1. E2:

(E20)
begin int i;
    proc side = int: (i:=1; i:=2, i);
    print ( side + side )
end

This will print either 3 or 4, for the reasons given in 3.7.1.

The advantage of this collateral elaboration from the point of view of implementation is that the order of elaboration can be chosen to be that which yields the minimum number of compiled instructions. For example:

(E21)
$y := x + a \times b$

Most compilers will choose to fetch and multiply *a* and *b* before getting hold of *x*.

### 5.7.4. Quaternaries — identity relations

Identity-relations are used to detect whether two names are identical:

(E22)
ref real anotherx = x; real y;
anotherx := x; c always yields true c
anotherx := y; c always yields false c
anotherx := y; c always yields false c

This example is quite trivial, because *anotherx* and *x*, by virtue of the identity-declaration, both yield the same name.
(E23) $xx := yy := x;$

(E24) $xx := x; \quad \dagger \text{ yields true} \quad \dagger$

(E25) $x :=: xx; \dagger \text{ yields true} \dagger$

(E26) $xx :=: yy \quad \dagger \text{ yields false} \quad \dagger$

In E24 and E25, xx was dereferenced to yield the name to which it
currently referred (i.e. x). It is permissible to dereference on one side of an
identity-relation, but not on both, and it is for this reason that E26 did not
work. E26 could never yield true, whatever assignations we might make to xx
and yy. However, by the use of casts we can achieve the result presumably
intended:

(E27) `ref real(xx) ::= ref real(yy) \&` yields true (in the context of E23) `\&`

The rules governing the use of an identity-relation are the following:

It has two sides – a strong side and a soft side. One of these can stand as the LHS, in which case the other must stand as the RHS. The symbol in between is either “::=” or “:=!” (which may alternatively be written as is or isn't).

For its strong side:

a) It must yield a name (i.e. its mode must be **ref amode**).

b) It must be a tertiary.

c) Its context is strong (so that dereferencing is allowed, and also `nil` (5.2.3)).

For its soft side:

a) It must yield a name, of the same mode as that yielded
by the strong side.

b) It must be a tertiary.

c) Its context is soft (so that deproceduring is the only possible coercion, and `nil` is not permitted).

As a whole, an identity-relation yields a **bool** value – **true** if the names match and the symbol in between is “::=” or if the names do not match and the symbol is “:=!”.

Here is a delicately balanced example:

(E28) `case i in xx, x or y out nil desac ::=`

`case j in yy, skip, heap ref real := x desac`

First, let us rewrite the example showing the a priori modes of all the items:
<table><tr><td>case i in xx,</td><td>¢ ref ref real</td><td>¢</td></tr><tr><td>x or y</td><td>¢ proc ref real</td><td>¢</td></tr><tr><td>out nil</td><td>¢ wait and see</td><td>¢</td></tr><tr><td>esac :=</td><td></td><td></td></tr><tr><td>case j in yy</td><td>¢ ref ref real</td><td>¢</td></tr><tr><td>skip,</td><td>¢ wait and see</td><td>¢</td></tr><tr><td>heap ref real:=x</td><td>¢ ref ref real</td><td>¢</td></tr></table>

Which is the soft side, and what is the mode of the name that it yields? Well, to put you out of your misery, the LHS is the soft one and the mode is *ref real*, but to obtain it we have to recall that case-clauses can be balanced (5.2.0.1) so that, even on the soft side, all but one of the items can be strongly coerced. Here then is the example again with all made clear:

<table><tr><td>case i in xx,</td><td>¢ strongly dereferenced</td><td>¢</td></tr><tr><td>x or y</td><td>¢ softly deprocedured</td><td>¢</td></tr><tr><td>out nil</td><td>¢ a strong context</td><td>¢</td></tr><tr><td>esac :=</td><td></td><td></td></tr><tr><td>case j in yy,</td><td>¢ strongly dereferenced</td><td>¢</td></tr><tr><td>skip,</td><td>¢ a strong context</td><td>¢</td></tr><tr><td>heap ref real :=x</td><td>¢ strongly dereferenced</td><td>¢</td></tr></table>

For an application of identity-relations, let us return to our list processing in E15. Let us assume all the declarations of E15 to have been made, and now continue thus:

<table><tr><td>(E29)</td><td>op eql = (union ( atom, ref cons ) a, b) bool:<br/>case a<br/>in (char c): (b | (char d): c=d, (int): false | b eql c),<br/>(int i): (b | (int j): i=j, (char): false | b eql i),<br/>(ref cons rc): car of rc eql b<br/>esac;<br/>comment this recursively defined (and probably not very<br/>efficient) operator compares two cars (or cdrs)<br/>of cons and yields true if they are, or refer to<br/>via a chain of cars, identical atoms comment<br/>ref cons a := list (("A", "X"));<br/>ref cons b := list (("B", "X"));<br/>cdr of cons (a) eql cdr of cons (b);<br/>¢ yields true because both sides refer to the value "X"<br/>¢<br/>cdr of cons (a) :=: cdr of cons (b)<br/>¢ yields false because both sides refer to different<br/>instances of the value "X"<br/>¢</td></tr></table>
The distinction here illustrates how, in list processing, it is often important to distinguish between a pointer to a list which is merely a copy of a given one, and a pointer which points to the given list itself. The identity-relation should be used to make this test.

Vertical readers, please turn to 6.7.
# 6. STANDARD PRELUDE

## 6.1. Operators

Each particular-program written by a user is presumed to be included within an "outer range", at the head of which is the standard-prelude (1.1) in which various standard declarations are made. These include:

* Standard constants (see 6.2 and 6.7)

* Standard procedures (see 6.2 and 6.7)

* Standard operators (see this section, and 6.3, 6.5 and 6.7)

* Additional constants and procedures required for transput (see 7).

Likewise, at the tail of the outer range, is a label stop:., to which you may jump in order to terminate the elaboration of your program, and which is followed by the standard-postlude (see 1.1 and Appendix 3).

We now set out, in tabular form, details of all the common operators (for the manner in which they are used in formulas see 5.1.3). The tables include, for completeness, all of the meanings which each operator can have, even though you may not yet be familiar with all of the modes involved. The meaning of each operator is given in the last column for those operators whose meaning is not obvious. If nothing appears in this column, it means that the generally accepted meaning applies, or that a similar operator has already been explained higher up the column.

There are sometimes several operators which perform the same function, in which case they are all given in the first column. Not all implementations will provide all the versions, however.

### 6.1.1. Monadic operators

<table><thead><tr><th>operator</th><th>priority</th><th>mode of a</th><th>mode of result</th><th>meaning</th></tr></thead><tbody><tr><td>~<br>~<br>not</td><td>10</td><td>bool<br>bits</td><td>bool<br>bits</td><td></td></tr><tr><td>+</td><td>10</td><td>int<br>real<br>compl</td><td>int<br>real<br>compl</td><td></td></tr><tr><td>-</td><td>10</td><td>int<br>real<br>compl</td><td>int<br>real<br>compl</td><td></td></tr></tbody></table>
<table><thead><tr><th>operator</th><th>priority</th><th>mode of a</th><th>mode of result</th><th>meaning</th></tr></thead><tbody><tr><td>bin</td><td>10</td><td>int</td><td>bits</td><td>the binary digits representing the positive integer a</td></tr><tr><td>re</td><td>10</td><td>compl</td><td>real</td><td>the real part</td></tr><tr><td>im</td><td>10</td><td>compl</td><td>real</td><td>the imaginary part</td></tr><tr><td>conj</td><td>10</td><td>compl</td><td>compl</td><td>re a i - im a</td></tr><tr><td rowspan="6">abs</td><td rowspan="6">10</td><td>bool</td><td>int</td><td rowspan="6">1 for true and 0 for false<br>sqrt(rea↑2 + ima↑2)<br>the opposite of bin<br>a unique integer for each<br>permissible value of char</td></tr><tr><td>int</td><td>int</td></tr><tr><td>real</td><td>real</td></tr><tr><td>compl</td><td>real</td></tr><tr><td>bits</td><td>int</td></tr><tr><td>char</td><td>int</td></tr><tr><td>arg</td><td>10</td><td>compl</td><td>real</td><td>the argument of a,<br>-π &lt; arg a &le; π</td></tr><tr><td>odd</td><td>10</td><td>int</td><td>bool</td><td>true if odd, false if even</td></tr><tr><td rowspan="2">sign</td><td rowspan="2">10</td><td>int</td><td>int</td><td rowspan="2">yields -1, 0, or +1</td></tr><tr><td>real</td><td>int</td></tr><tr><td>round</td><td>10</td><td>real</td><td>int</td><td>the nearest integer</td></tr><tr><td>entier</td><td>10</td><td>real</td><td>int</td><td>the integer equal to a, or<br>the next integer below<br>(more negative than) a</td></tr><tr><td>repr</td><td>10</td><td>int</td><td>char</td><td>the opposite of abs of a<br>char</td></tr></tbody></table>

### 6.1.2. Dyadic operators

<table><thead><tr><th>operator</th><th>priority</th><th>mode of a</th><th>mode of b</th><th>mode of result</th><th>meaning</th></tr></thead><tbody><tr><td>i</td><td>9</td><td>real</td><td>real</td><td>compl</td><td>a plus i times b</td></tr><tr><td>⊥</td><td></td><td>int</td><td>int</td><td>compl</td><td></td></tr><tr><td>+x</td><td></td><td>int</td><td>real</td><td>compl</td><td></td></tr><tr><td>++</td><td></td><td>real</td><td>int</td><td>compl</td><td></td></tr></tbody></table>
<table><thead><tr><th>operator</th><th>priority</th><th>mode of a</th><th>mode of b</th><th>mode of result</th><th>meaning</th></tr></thead><tbody><tr><td>↑<br>**<br>up</td><td>8</td><td>int<br>real<br>compl</td><td>int<br>int<br>int</td><td>int<br>real<br>compl</td><td>a<sup>b</sup> where b ≥ 0<br>a<sup>b</sup><br>a<sup>b</sup></td></tr><tr><td>↑<br>shl<br>up</td><td></td><td>bits</td><td>int</td><td>bits</td><td>a shifted left b places (or right for b negative)</td></tr><tr><td>↓<br>shr<br>down</td><td>8</td><td>bits</td><td>int</td><td>bits</td><td>a shifted right b places (or left for b negative)</td></tr><tr><td>÷<br>%<br>over</td><td>7</td><td>int</td><td>int</td><td>int</td><td>abs (a ÷ b) = entier abs (a/b)<br>i.e. truncation towards<br>zero</td></tr><tr><td>mod<br>÷x<br>÷*<br>%x<br>%*</td><td>7</td><td>int</td><td>int</td><td>int</td><td>0 ≤ a mod b &lt; b</td></tr><tr><td>x<br>*</td><td>7</td><td>int<br>real<br>compl<br>real<br>int<br>compl<br>compl<br>int<br>real<br>string<br>int<br>char<br>int</td><td>int<br>real<br>compl<br>int<br>real<br>int<br>real<br>compl<br>compl<br>compl<br>compl<br>int<br>string<br>int<br>char</td><td>int<br>real<br>compl<br>real<br>real<br>compl<br>compl<br>compl<br>compl<br>string<br>string<br>string<br>string</td><td>a replicated b times<br>b replicated a times</td></tr><tr><td>/</td><td>7</td><td>int<br>real<br>compl<br>real<br>int<br>compl<br>compl<br>int<br>real</td><td>int<br>real<br>compl<br>int<br>real<br>int<br>real<br>compl<br>compl</td><td>real<br>real<br>compl<br>real<br>real<br>compl<br>compl<br>compl<br>compl</td><td></td></tr><tr><td>elem<br>□</td><td>7</td><td>int<br>int</td><td>bits<br>bytes</td><td>bool<br>char</td><td>the a th bit of b<br>the a th char of b</td></tr></tbody></table>
<table><thead><tr><th>operator</th><th>priority</th><th>mode of a</th><th>mode of b</th><th>mode of result</th><th>meaning</th></tr></thead><tbody><tr><td>+</td><td>6</td><td>int<br>real<br>compl<br>real<br>int<br>compl<br>compl<br>int<br>real<br>compl<br>string<br>string<br>char<br>char</td><td>int<br>real<br>compl<br>int<br>real<br>compl<br>real<br>compl<br>string<br>char<br>string<br>char</td><td>int<br>real<br>compl<br>real<br>compl<br>compl<br>compl<br>string<br>string<br>string<br>string</td><td>the concatenation<br>of a and b</td></tr><tr><td>-</td><td>6</td><td>int<br>real<br>compl<br>real<br>int<br>compl<br>compl<br>int<br>real</td><td>int<br>real<br>compl<br>int<br>real<br>compl<br>real<br>compl</td><td>int<br>real<br>compl<br>real<br>compl<br>compl<br>compl</td><td></td></tr><tr><td>&lt;<br>lt</td><td>5</td><td>int<br>real<br>real<br>int<br>char<br>string<br>string<br>char<br>bytes</td><td>int<br>real<br>int<br>real<br>char<br>string<br>char<br>string<br>bytes</td><td>bool<br>bool<br>bool<br>bool<br>bool<br>bool<br>bool<br>bool</td><td>true if abs a &lt; abs b<br>true if the first character<br>in a that differs from the<br>corresponding character<br>in b is less than same</td></tr><tr><td>&gt;<br>gt</td><td>5</td><td>int<br>real<br>real<br>int<br>char<br>string<br>string<br>char<br>bytes</td><td>int<br>real<br>int<br>real<br>char<br>string<br>char<br>string<br>bytes</td><td>bool<br>bool<br>bool<br>bool<br>bool<br>bool<br>bool<br>bool</td><td></td></tr><tr><td>&lt;=<br>le</td><td>5</td><td>int<br>real<br>real<br>int<br>bits<br>char<br>string<br>string<br>char<br>bytes</td><td>int<br>real<br>int<br>real<br>bits<br>char<br>string<br>char<br>string<br>bytes</td><td>bool<br>bool<br>bool<br>bool<br>bool<br>bool<br>bool<br>bool</td><td>true if each bit in a implies<br>the corresponding bit in b</td></tr></tbody></table>