_    __    ___  
   / \  / /_  ( _ ) 
  / _ \| '_ \ / _ \           On Algol 68 multiples, and ghosts
 / ___ \ (_) | (_) |
/_/   \_\___/ \___/ 
                    

                                                      Jose E. Marchesi
                                                       January 1, 2026


This article  provides a  somewhat detailed  introduction to  Algol 68
"multiples", the data  structures that roughly correspond  to what are
commonly known  as "arrays" in  other programming languages,  but that
differ from  these in  several peculiar  and interesting  aspects.  It
then also discusses some aspects on how better implement them, and the
realization in the GNU Algol 68 compiler based in GCC.

Rows and multiples

We will start by establising a clear separation of two different concepts that are sometimes muddled in other programming languages: that of the type of a value and the kind of a value itself. Data types are called "modes" in Algol 68. Each mode defines a set of static properties that apply to values which are "acceptable" to that mode. An integral value 12, for example, is acceptable to the mode 'int'. In other programming languages we would say that 12 is a value of type int. As such, modes only exist at compile-time [1], and guide the compiler to generate code such as the static properties of the values acceptable to these modes are always preserved. The particular values acceptable to that mode, created and manipulated by the program, on the other hand, are internal objects and exist at run-time. Formal declarers for row modes:
[]int                     { row of integers }
[][]int                   { row of row of integers }
[,]int                    { row row of integers }
The bounds of multiples are dynamic up to the point the value gets generated. Once the multiple comes to existence, its bounds stay the same and cannot be changed. What is more, a name that refers to a multiple can only be made to refer to another multiple having exactly the same bounds. For example, consider the following name that refers to a multiple of three reals yielded by a sample generator:
[3]real vector;
At the point the multiple gets generated, it contains three undefined reals. In the case of GCC, these reals are all 0.0. We can now use an assignation to supercede the multiple referred by that name. For example:
vector := (1,0,1);
Assigning a multiple value involves checking the bounds of the value being assigned, to make sure they match exactly with the bounds of the value being superceded. In this case, the bounds of the assigned value are '1:3', which match with the bounds of the original '(0.0,0.0,0.0)'. The assignation is valid and is carrief forward. Thereafter the name 'vector' will refer to (a copy of) the value '(1.0,0.0,1.0)'. Had we written instead:
vector := (1,0);
We would then have triggered a run-time error complaining about the disparity of bounds: you cannot make the name to refer to a multiple of two reals. Since assignation is the only way provided by the language to supercede the value referred by a name, this check is enough to guarantee that once a name is made to refer to some given multiple, it will always refer to multiples having the same number of elements. This explains why the bounds of a multiple are not a property part of the mode they are acceptable to, but only of the particular multiple value. This is not to be confused with the rank of the multiple, which is in fact a static property of the row mode and therefore checked at compile-time.
Footnotes: [1] United modes, whose values include an overhead that identify the mode of the value currently stored, refer to modes but only indirectly and always relative to the acceptable modes, so this statement still holds true.