# Informal Introduction to ALGOL 68

C. H. Lindsey, S. G. van Der Meulen

► To cite this version:

C. H. Lindsey, S. G. van Der Meulen. Informal Introduction to ALGOL 68. North-Holland, pp.370, 1977, 0720407265. hal-03027689

HAL Id: hal-03027689

https://inria.hal.science/hal-03027689

Submitted on 27 Nov 2020

HAL is a multi-disciplinary open access
archive for the deposit and dissemination of sci-
entific research documents, whether they are pub-
lished or not. The documents may come from
teaching and research institutions in France or
abroad, or from public or private research centers.

L'archive ouverte pluridisciplinaire HAL, est
destinée au dépôt et à la diffusion de documents
scientifiques de niveau recherche, publiés ou non,
émanant des établissements d'enseignement et de
recherche français ou étrangers, des laboratoires
publics ou privés.

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

Distributed under a Creative Commons Attribution 4.0 International License
lindsey
v.d. meulen

informal introduction to
ALGOL 68
informal
introduction
to
ALGOL 68 by

c.h. lindsey and
s.g. van der meulen

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

IFIP

REVISED

north-holland
INFORMAL INTRODUCTION TO ALGOL 68
REVISED EDITION
<figure><img src="image_3.png" /></figure>
INFORMAL INTRODUCTION

to ALGOL 68

C. H. LINDSEY

*Department of Computer Science, University of Manchester*

S. G. van der MEULEN

*Department of Informatics, University of Utrecht*

Revised Edition

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

NORTH-HOLLAND PUBLISHING COMPANY
AMSTERDAM · NEW YORK · OXFORD
© IFIP, 1977

All rights reserved. No part of this publication may be reproduced, stored in a
retrieval system, or transmitted, in any form or by any means, electronic,
mechanical, photocopying, recording or otherwise, without the prior permission of
the copyright owner.

North-Holland ISBN 0 7204 0726 5

First edition 1971

Revised reprint 1973

Second completely revised edition 1977

Revised reprint 1980, second printing 1981

Published by:

NORTH-HOLLAND PUBLISHING COMPANY,
AMSTERDAM, NEW YORK, OXFORD.

Sole distributors for the U.S.A. and Canada:

Elsevier/North-Holland Inc.
52, Vanderbilt Avenue
New York, NY 10017

Library of Congress Cataloging in Publication Data

Lindsey, C.H.

Informal introduction to ALGOL 68.

Authors' names in reverse order in previous ed.

Includes index.

1. ALGOL (Computer program language)

2. Electronic digital computers-Programming.

I. Meulen, S.G. van der, joint author. II. Title.

QA76.73:A24M47 1977 001.6'424 78-148532

ISBN 0-7204-0504-1

ISBN 0-7204-0726-5 pbk.

PRINTED IN THE NETHERLANDS
To the uninitiated reader
ACKNOWLEDGEMENTS

The Authors wish to thank Prof. Dr. A. van Wijngaarden and the other authors of the ALGOL 68 Report, and also the many members of WG 2.1 and others in the computing community who read this Introduction in draft form and in its first edition, for their encouragement and helpful criticisms of the text. The Mathematical Centre, Amsterdam are particularly thanked for their assistance in reproducing the drafts of the first edition. The authors also wish to acknowledge the official support accorded to this work by IFIP TC-2 and WG-2.1.
PREFACE

Publication of this volume represents a major step in making accessible to the international computing community the operational content of the "Revised Report on the Algorithmic Language ALGOL 68". The Report itself is, of course, an unparalleled accomplishment in the literature of programming languages as a defining document. The complexity of the topic, however, necessarily disqualifies such a completely rigorous treatment from consideration as a general pedagogical device; hence the present volume.

As noted by the authors, this book "is not - and is not intended to be - a primer for the programming novice". This is as it should be. The Revised Report addresses those who must understand every nuance of the language; primarily language designers and compiler implementers. If implementations of ALGOL 68 are to be other than academic exercises, there is a pressing need to acquaint the set of people who write computer programs as a routine part of their daily lives with the essential elements of the language. This book can do just that.

The algorithmic language, ALGOL 68, stands as a major product of the International Federation for Information Processing, an organization now in its second decade, counting among its members the national information processing societies from thirty-four countries spread over all six of the world's inhabited continents. Among the principal activities of the Federation is the work of Technical Committee 2, Programming Languages, and its Working Group 2.1, ALGOL. The initial effort of WG 2.1 stemmed from the development of the algorithmic language ALGOL 60, and since 1964 under the Chairmanships of Prof. Dr. W.L. van der Poel, Prof. Dr. M. Paul and currently Prof. J.E.L. Peck, this group of international experts, including the authors of the present work, has been engaged in the design and development of ALGOL 68.

While the present book is wholly the work of the two authors, it has been extensively reviewed in manuscript by the Working Group and has the status of a working paper within the group. It follows that the accuracy with which it represents ALGOL 68 is far higher than might be apparent from its cover. Every effort has been made to ensure that the book contains a comprehensive, accurate and readable introduction to the language. Having had the opportunity to observe this effort closely from my position as Chairman of TC-2, I can assure the reader that the authors have been successful in this endeavor.

T.B. Steel, Jr.

New York, May 20, 1976
## FOREWORD

The algorithmic language ALGOL 68 was designed by Working Group 2.1 of the International Federation for Information Processing, and formally defined in a Report* published early in 1969. The first edition of the present text was a companion volume to that Report.

Since that time the language, in whole or in part, has been implemented on a variety of computers and substantial experience has been gained of its use. One leading computer manufacturer has released an implementation in virtual complete agreement with the current official definition, and it should only be a matter of time before others follow.

The experience of implementation and use led to many proposals for changes to the language and these were incorporated in the text of a Revised Report approved at the Los Angeles meeting of the Working Group in 1973. The "Revised Report on the Algorithmic Language ALGOL 68"† (hereafter referred to as simply "the Report") is now the official, rigorous and final definition of the machine-independent programming language ALGOL 68.

This "Informal Introduction to ALGOL 68" seeks to describe, rather than to define, the revised language. If you have some difficulty in understanding the Report, it is our hope that you will find our informal treatment more palatable, even though this may have been achieved at the expense of rigour. It is the companion volume referred to in Section R.0.1.1 of the Report. (We shall always precede our references to the Report with such an R. All other references are to the present text.)

This introduction, however, is not — and is not intended to be — a primer for the programming novice. The "user" to whom we address ourselves is assumed to be a "programmer", i.e. someone who is able to write, or at least to read, a text in some machine-independent programming language which is on a level not too much below, for instance, ALGOL 60. Our aim has been to describe the whole of ALGOL 68, and this Introduction may also therefore have some merit as a work of reference — provided it is always understood that the official Report is the final arbiter in all cases of doubt.

<footnote>* A. van Wijngaarden (ed.), B.J. Mailloux, J.E.L. Peck, C.H.A. Koster, Report on the algorithmic language ALGOL 68, *Numer. Math.* 14 (1969) 79-218; also in *Kibernetika* 6 (1969) and 7 (1970).</footnote>

<footnote>† A. van Wijngaarden, B.J. Mailloux, J.E.L. Peck, C.H.A. Koster, M. Sintzoff, C.H. Lindsey, L.G.L.T. Meertens and R.G. Fisker, Revised report on the algorithmic language ALGOL 68, *Acta Informat.* 5 (1975) parts 1-3 (reprints published by Springer, Berlin, and also as Mathematical Centre Tract 50 by the Mathematisch Centrum, Amsterdam); also in *SIGPLAN Notices* 12 (5) (1977).</footnote>
TABLE OF CONTENTS

PREFACE

FOREWORD

0. A VERY INFORMAL

INTRODUCTION

<table><thead><tr><th></th><th>x.1. FUNDAMENTALS</th><th>x.2. PROCEDURES AND NAMES</th><th>x.3. OPERATIONS</th><th>x.4. STRUCTURES</th><th>x.5. MULTIPLE VALUES</th><th>x.6. UNIONS</th><th>x.7. DISTINCTIVE FEATURES</th></tr></thead><tbody><tr><td>1.y. BASIC CONCEPTS</td><td>1.1. FUNDAMENTALS<br>1.1.1. Objects<br>1.1.2. Identifiers<br>1.1.2.1. Variable declarations<br>1.1.2.2. Assignment, collateral elaboration<br>1.1.3. Phrases, serial and collateral elaboration<br>1.1.4. Routines<br>1.1.5. Defining and applied occurrences<br>1.1.6. Coercion</td><td>1.2. NAMES AND DECLARERS<br>1.2.1. Ascription and assignment<br>1.2.2. Identity declarations<br>1.2.2.1. Constants<br>1.2.2.2. Equivalences<br>1.2.2.3. Local generators<br>1.2.2.4. Variables and names<br>1.2.2.5. Casts<br>1.2.3. The metanotation MODE<br>1.2.3.1. proc modes<br>1.2.3.2. The supply of the actual parameters<br>1.2.4. Summary</td><td>1.3. SYMBOLS, MODES AND OPERATORS<br>1.3.1. Representations<br>1.3.2. Symbols, bold words and comments<br>1.3.3. Other declarations<br>1.3.3.1. Mode declarations<br>1.3.3.2. Operation declarations<br>1.3.3.3. Priority declarations</td><td>1.4. STOWED VALUES, STRUCTURES<br>1.4.0. STOWED values<br>1.4.1. Enumeration by tagging<br>1.4.1.1. Structured constants<br>1.4.1.2. Names of structures<br>1.4.1.3. Creation of new structures<br>1.4.2. Different objects in one box<br>1.4.3. Chaining<br>1.4.4. Pandora's boxes</td><td>1.5. STOWED VALUES, MULTIPLES<br>1.5.1. Multiple values and descriptors<br>1.5.2. Indexing<br>1.5.2.1. Indexers<br>1.5.2.2. Subscripting<br>1.5.2.3. Trimming<br>1.5.3. Identifier declarations for multiples<br>1.5.4. Slices<br>1.5.5. Interrogations</td><td>1.6. UNIONS<br>1.6.1. United modes<br>1.6.1.1. United constants<br>1.6.1.2. Equivalence of unions<br>1.6.1.3. Local united generation<br>1.6.2. Assignations and conformity clauses</td><td>1.7. DISTINCTIVE FEATURES<br>1.7.1. The long and short modes<br>1.7.2. Identity relations</td></tr><tr><td>2.y. DECLARATIONS</td><td>2.1. PRIMITIVE DECLARATIONS<br>2.1.1. Primitives<br>2.1.2. Variable declarations<br>2.1.3. Sample declarations</td><td>2.2. IDENTITY DECLARATIONS<br>2.2.1. Identity declarations<br>2.2.2. Another look at variable declarations<br>2.2.3. Initialised variable declarations</td><td>2.3. MODE DECLARATIONS</td><td>2.4. STRUCTURE DECLARATIONS<br>2.4.1. struct declarations<br>2.4.2. struct declarations<br>2.4.3. Well formed modes<br>2.4.4. The mode compl</td><td>2.5. MULTIPLE DECLARATIONS<br>2.5.1. Row declarers<br>2.5.2. Row declarations<br>2.5.2.1. Fixed and flexible names<br>2.5.2.2. Actual 'row of' declarers<br>2.5.2.3. Summary<br>2.5.3. The mode string</td><td>2.6. UNION DECLARATIONS<br>2.6.1. union declarers<br>2.6.2. union declarations</td><td>2.7. BITS, BYTES, LONGS AND SHORTS<br>2.7.1. bits and bytes<br>2.7.2. long and short modes<br>2.7.3. heap declarations</td></tr><tr><td>3.y. CLAUSES</td><td>3.1. SERIAL CLAUSES<br>3.1.1. The declarations<br>3.1.2. The statements<br>3.1.3. The yield<br>3.1.4. Completers<br>3.1.5. Delimiters</td><td>3.2 CLOSED CLAUSES<br>3.2.1. Ranges and reaches<br>3.2.2. Scopes of names<br>3.2.3. Identification<br>3.2.4. ENCLOSED clauses<br>3.2.4.1. Closed clauses<br>3.2.4.2. Conditional clauses<br>3.2.4.3. Case clauses</td><td>3.3. BOLD WORDS<br>3.3.1. Identification of mode indications</td><td>3.4. STRUCTURE DISPLAYS</td><td>3.5. ROW DISPLAYS AND LOOPS<br>3.5.1. Row displays<br>3.5.2. Loop clauses</td><td>3.6. CONFORMITY CLAUSES</td><td>3.7. COLLATERALITY<br>3.7.1. Collateral clauses<br>3.7.2. Parallel clauses</td></tr><tr><td>4.y. ROUTINES</td><td>4.1. PROCEDURES AND OPERATORS<br>4.1.1. Standard prelude routines</td><td>4.2. PROCEDURE DECLARATIONS<br>4.2.1. proc declarers<br>4.2.2. Routines<br>4.2.2.1. Routine texts<br>4.2.2.2. Calling<br>4.2.2.3. Recursion<br>4.2.3. Scopes of routines</td><td>4.3. OPERATION DECLARATIONS<br>4.3.1. Priority declarations<br>4.3.2. Operation declarations<br>4.3.3. Identification of operators</td><td>4.4. skip</td><td>4.5. ROW-OF PARAMETERS</td><td>4.6. skip</td><td>4.7. JUMPS<br>4.7.1. Simple jumps<br>4.7.2. Procedure jumps</td></tr><tr><td>x.1. FUNDAMENTALS</td><td>x.2. PROCEDURES AND NAMES</td><td>x.3. OPERATIONS</td><td>x.4. STRUCTURES</td><td>x.5. MULTIPLE VALUES</td><td>x.6. UNIONS</td><td>x.7. DISTINCTIVE FEATURES</td></tr><tr><td>5.y. UNITS</td><td>5.1. SIMPLE UNITS</td><td>5.2 BALANCE AND CALL</td><td>5.3. skip</td><td>5.4. UNITS AND STRUCTURES<br>5.4.0. Complex widening</td><td>5.5. UNITS AND MULTIPLES<br>5.5.0. Rowing</td><td>5.6. UNITS AND UNIONS<br>5.6.0. Uniting</td><td>5.7. BITS AND PIECES OF GARBAGE<br>5.7.0.1. Voiding<br>5.7.0.2. bits and bytes widening</td></tr><tr><td>5.y.0. Coercion</td><td>5.1.0.1. Coercends<br>5.1.0.2. Coercion<br>5.1.0.3. Dereferencing<br>5.1.0.4. Widening</td><td>5.2.0.1. ENCLOSED clauses and balancing<br>5.2.0.2. Deproceduring</td><td></td><td></td><td></td><td></td><td></td></tr><tr><td>5.y.1. Primaries</td><td>5.1.1.1. Denotations<br>5.1.1.2. Applied identifiers<br>5.1.1.3. Casts</td><td>5.2.1. Procedure calls</td><td></td><td>5.4.1. Applied identifiers<br>5.4.2. Selections</td><td>5.5.1.1. String denotations<br>5.5.1.2. Applied identifiers<br>5.5.1.3. Slices<br>5.5.2. Multiple selections</td><td></td><td>5.7.1.1. bits denotations<br>5.7.1.2. long and short denotations<br>5.7.2.1. loc generators<br>5.7.2.2. heap generators<br>5.7.3. Order of elaboration of operands</td></tr><tr><td>5.y.2. Secondaries</td><td>5.1.2. Secondaries</td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td>5.y.3. Tertaries</td><td>5.1.3. Formulas</td><td>5.2.3. nil</td><td></td><td>5.4.3. Formulas with complex operators</td><td>5.5.3. Bound interrogations<br>5.5.4.1. Flexible assignments<br>5.5.4.2. Assignment to slices<br>5.5.4.3. Overlapping slices</td><td>5.6.4. Assignations of unions of rows</td><td>5.7.4. Identity relations</td></tr><tr><td>5.y.4. Quarters-aries</td><td>5.1.4.1. Assignations<br>5.1.4.2. skip</td><td>5.2.4. Assignations involving names</td><td></td><td></td><td></td><td></td><td></td></tr><tr><td>6.y. STANDARD PRELUDE</td><td>6.1 OPERATORS<br>6.1.1. Monadic operators<br>6.1.2. Dyadic operators</td><td>6.2. CONSTANTS AND PROCEDURES<br>6.2.1. Constants<br>6.2.2. Procedures</td><td>6.3. ASSIGNING OPERATORS</td><td>6.4. skip</td><td>6.5. INTERROGATIONS<br>6.5.1. Dyadic operators<br>6.5.2. Monadic operators</td><td>6.6. skip</td><td>6.7. LONG OPERATORS<br>6.7.1. Environment enquiries<br>6.7.2. Procedures<br>6.7.3. Operators<br>6.7.4. length and shorten<br>6.7.5. up and down</td></tr><tr><td>7.y. TRANSPUT</td><td>7.1 FORMATLESS TRANSPUT<br>7.1.1. Formatless output<br>7.1.2. Formatless input</td><td>7.2. FILES<br>7.2.1. Channels, books and files<br>7.2.2. Environment enquiries<br>7.2.3. Procedures for opening and closing<br>7.2.4. Position enquiries<br>7.2.5. Layout routines</td><td>7.3. skip</td><td>7.4. STRUCTURES AND EVENTS<br>7.4.1. Straightening of structures<br>7.4.2. Files<br>7.4.3. Code conversion<br>7.4.4. Event routines<br>7.4.4.1. On logical file end<br>7.4.4.2. On physical file end<br>7.4.4.3. On page end<br>7.4.4.4. On line end<br>7.4.4.5. On format end<br>7.4.4.6. On value error<br>7.4.4.7. On char error</td><td>7.5. ROWS AND STRINGS<br>7.5.1. Straightening of multiple values<br>7.5.2. Conversion procedures<br>7.5.3. Conversion environment enquiries</td><td>7.6. FORMATTED TRANSPUT<br>7.6.1. format texts<br>7.6.1.1. Literals<br>7.6.1.2. Alignments<br>7.6.1.3. Frames<br>7.6.1.4. Replicators and collections<br>7.6.2. formats<br>7.6.3. The formatted transput procedures<br>7.6.4. Events</td><td>7.7. BINARY TRANSPUT<br>7.7.1. Binary transput procedures<br>7.7.2. Some restrictions</td></tr><tr><td>8.y. EXAMPLES</td><td>8.1. SIMPLE EXAMPLES</td><td>8.2. PROCEDURE EXAMPLES<br>8.2.1. Easter</td><td>8.3. EXAMPLES OF OPERATORS<br>8.3.1. Parallel plus</td><td>8.4. TWO EXAMPLES OF LIBRARY PRELUDES<br>8.4.1. Operations on vectors in E<sub>3</sub><br>8.4.1.1. Comments on 8.4.1.<br>8.4.1.2. An example of the use of vecs<br>8.4.2. Operations on rational operands<br>8.4.2.1. Comments on the library prelude 8.4.2.<br>8.4.2.2. Some remarks on the use of rationals</td><td>8.5. A LIBRARY PRELUDE FOR VECTOR AND MATRIX OPERATIONS IN E<sub>n</sub><br>8.5.1. Operations on vectors in E<sub>n</sub><br>8.5.2. Operations on matrices and vectors<br>8.5.3. Operations on square matrices</td><td>8.6. EXAMPLES OF TRANSPUT<br>8.6.1. The happy family</td><td>8.7. EXAMPLES OF EVERYTHING<br>8.7.1. Analytic differentiation</td></tr><tr><td>APPENDICES</td><td>APPENDIX 1<br>Alternative representations</td><td>APPENDIX 2<br>Sample declarations</td><td>APPENDIX 3<br>Glossary<br>1. Internal objects and modes<br>2. External objects<br>3. Technical terms</td><td>APPENDIX 4<br>The sublanguage</td><td>APPENDIX 5<br>The standard hardware representation</td><td>APPENDIX 6<br>Syntax charts</td><td></td></tr></tbody></table>
<figure><img src="image_5.png" /></figure>
# 0. VERY INFORMAL INTRODUCTION TO ALGOL 68

## Contents

0.0 Introduction

0.1 A simple program

0.2 The primitive modes, denotations

0.2 .1 bool

0.2 .2 int

0.2 .3 real

0.2 .4 char

0.2 .5 bool, int, real and char

0.3 Loops

0.4 The creation of new modes, multiples

0.4 .1 Multiples

0.4 .2 New mode indications

0.4 .3 Multiples with flexible bounds, strings

0.5 The value of a unit

0.5 .1 The value of a formula

0.5 .2 The value of a conditional clause

0.5 .3 The value of a serial clause

0.5 .4 The value of a closed clause

0.5 .5 The value of a constant

0.6 A more involved program

0.7 Routines and procedures

0.7 .1 Procedures without parameters

0.7 .2 Procedures with parameters

0.7 .3 Examples of procedure declarations

0.8 The creation of new modes, names and values referred to

0.8 .1 Variable declarations revisited

0.8 .2 Procedures, values and references

0.8 .3 Procedures as formal parameters

0.8 .4 Pointers (variable names)

0.8 .5 Identity relators, the cast, coercion

0.9 Structures and other new modes

0.9 .1 complex values, vectors etc.

0.9 .2 Structures with mixed mode fields, chains etc.
<table><tr><td>0.10</td><td>Routines and operators</td></tr><tr><td>0.10.1</td><td>Operations on boolean operands</td></tr><tr><td>0.10.2</td><td>Formulae</td></tr><tr><td>0.10.3</td><td>Operations on arithmetic operands, the standard prelude</td></tr><tr><td>0.10.4</td><td>Operations on complex operands</td></tr><tr><td>0.10.5</td><td>Operations combined with assignations</td></tr><tr><td>0.10.6</td><td>Operations on strings</td></tr><tr><td>0.10.7</td><td>The library prelude</td></tr><tr><td>0.11</td><td>bits and bytes, longs and shorts</td></tr><tr><td>0.11.1</td><td>The modes bits and bytes</td></tr><tr><td>0.11.2</td><td>The long and short modes</td></tr><tr><td>0.12</td><td>Unions</td></tr><tr><td>0.13</td><td>Local and global generators, stack and heap</td></tr><tr><td>0.14</td><td>What to do next</td></tr></table>

## 0.0. Aims and methods

Since ALGOL 68 is a highly recursively structured language, it is quite impossible to describe it until it has been described. So that you can read this Introduction without tying your own mental processes into a recursive knot, it has been laid out to a certain pattern, which we ask you to follow. Please, therefore, start by reading once or twice "Very Informal Introduction", in which we try to give a broad survey of what is in this language – mainly by the way of small examples and plain explanations. After that, we shall tell you what to do next.

if you think you know it all already

then read (what to do next) comment Section 0.14 comment

fi
## 0.1. A simple program

(E1)
begin
    loc real x, y, z;
    read (x); read (y);
    z := (x + y) / 2 - sqrt(x * y);
    print (z);
end

This piece of text represents a program, and as such it defines a sequence of actions to be performed by a computer. This sequence of actions is termed "the elaboration of the program". We shall briefly outline the elaboration of E1:

1. Three identifiers x, y and z for real variables are declared. That is to say that somewhere in the memory of our computer, in the "stack", three locations for real values are reserved. These values are referred to by the names x̂, ŷ and ẑ (i.e. by their "addresses") which are also entities (values) in the computer. It thus appears that a 'variable' consists of a value associated with the name which refers to it. You may consider the identifiers x, y and z as the representatives in the programtext of the names x̂, ŷ and ẑ.

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

The names x̂, ŷ and ẑ "refer to" real values (see also Section 0.8).
2. Next, from a punched tape, or punched card or some other medium, two numbers are read in and assigned to x and y. That is to say, these numbers are converted into the proper bit-patterns in the private internal number-system of the computer, which subsequently are stored in the locations corresponding to the names $\tilde{x}$ and $\tilde{y}$:

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

3. Then, the difference between the arithmetic and geometric mean of these values is calculated and assigned to z, so that we find this difference in the location corresponding to $\tilde{z}$:

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

4. Finally, this value, referred to by $\tilde{z}$, is reconverted into humanly recognizable graphics and is printed by some device:

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

Summing up we have:

1. Three variable-declarations.

2. Two input statements.
3. An assignation. To the left of the becomes-symbol `:=` we find the destination z, and to the right a 'formula' whose value is to be assigned to that destination.

4. An output statement.

The three variable-declarations in the first line are separated by and-also-symbols, represented by commas. This means that they are elaborated "collaterally", which is a technical term stating that the order of their elaboration is not prescribed.

The collateral declaration in the first line, the input statements in the second, the assignation in the third, and the output statement in the last line are separated by go-on-symbols (represented by semicolons). This means that they are elaborated "serially". This again is a technical term stating that the order in which these phrases are elaborated is explicitly prescribed to be the textual order: one after the other. They form a 'serial-clause'.

The piece of text E1 might very well be part of a larger program. The meaning of the identifiers x, y and z (and consequently the existence of the names ȳ, ȳ and ȳ̄ and of the real values referred to by them) is, however, local: i.e. the "reach" of their declarations is limited to the serial-clause between *begin* and *end*, which delimit a 'closed-clause'. If outside this closed-clause (or inside another closed-clause contained within it) other identifiers x, y and z should be declared, then these have nothing to do with those declared in example E1. We say, therefore, that the original meaning of x, y and z applies only to that part of the program text.

The standard input procedure *read* accepts as actual parameter not only the name of a real value, but also (amongst many others) a 'row-display' like (x,y).

Consequently, line 2 may be replaced by:

*read((x,y));* Observe that we again give precisely one actual-parameter to *read*; instead of one name, one row-display of names.

Instead of the two phrases 3 and 4 we might write, in one statement:

*print(z:=(x+y)/2-sqrt(x*y));*

Instead of the *begin* and *end* we may write *(* and *).* Thus E1* below is, at least in its effect, completely equivalent to E1:

(E1*) ( loc real x, y, z; read((x,y)); . print(z:=(x+y)/2-sqrt(x*y)) )
And now we discover that z became superfluous, so that we can write:

(E1**) ( loc real x, y; read((x,y)); print((x+y)/2-sqrt(x×y)) )

## 0.2. The primitive modes, denotations

The real in E1 specifies a mode (i.e. it specifies that ȳ, ý and ž will refer to values which belong to a certain class). An infinite number of distinct modes (disjoint classes of values) is provided in this language. They are, however, derived from the primitive modes (which form the basis of the entire mode system): boolean (**bool**), integral (**int**), real (**real**), character (**char**) and a few others (see 0.11).

For these primitive modes we have 'denotations': symbols or sequences of symbols yielding a specific value in such a mode.

### 0.2.1. bool

There are two boolean values, denoted by the symbols **true** and **false**.

If (in E2 below) *C* is a piece of program yielding a boolean value, then this value is either **true** or **false**. In a 'conditional-clause' like:

(E2) if *C* then *Ctrue* else *Cfalse* fi

first of all *C* is elaborated, being the condition between **if** and **then**. The then-part *Ctrue* between **then** and **else** is elaborated only if the condition yielded **true**. The else-part *Cfalse* between **else** and *fi* is elaborated only if the condition yielded **false**.

The symbols **if** and **then**, **then** and **else**, **else** and **fi** enclose clauses in which new identifiers of local reach may be declared as in a closed-clause (they form pairs of brackets, so to speak). Observe that the whole conditional-clause is enclosed between **if** and **fi**. The else-part may be absent, in which case the then-part is closed by **fi**; the then-clause must always be there.

For E2 we may also write:

(E2*) ( *C* | *Ctrue* | *Cfalse* )

which may be a fine notation to use in a formula, where either the value of *Ctrue* or the value of *Cfalse* is to be yielded (see 0.5.2).
### 0.2.2. int

There will be many integral values, denoted by:

0 1 2 3 4 5 6 7 8 9 10 11 12 --- --- --- 2147483647 ---

How far can we go? The Report does not answer this question. It depends entirely on the implementation. It is, however, prescribed that we can always know the largest integral value by an "environment enquiry" max int, which is a standard identifier yielding the largest integral value in a specific implementation (see also 0.11.2).

Observe that there is no sign preceding an integral-denotation. Of course you may write:

+1 -37 -1000 +534711 -513617 etc.

but then the + and the - are monadic-operators applied to the value denoted.

Let (in E3 below) *I* be a piece of program yielding an integral value and let *S* be another piece of program; let *I1*, *I2*, *I3*, ..., *Ik* be certain phrases. In a 'case-clause' like:

(E3) case *I* in *I1*, *I2*, *I3*, ..., *Ik*
out *S*
esac

first of all *I* is elaborated. If its yield is less than *I* (i.e. 0 or -1 or -2 etc) or greater than *k* (i.e. *k* + 1 etc), then the out-part *S* will be elaborated; if, to the contrary, the yield of *I* is one of the values 1 or 2 or 3 or ... or *k*, then the corresponding phrase in the in-part will be elaborated.

The symbols **case** and **in** and also **out** and **esac** enclose clauses in which new identifiers of local reach may be declared as in a closed-clause or conditional-clause. The whole case-clause is enclosed between **case** and **esac**. The out-part (in E3 **out S**) may be absent, in which case the in-part is closed by **esac**; the in-part must always be there containing at least two phrases.

For E3 we may also write:

(E3*) ( *I* | *I1*, *I2*, *I3*, ..., *Ik* | *S* )

### 0.2.3. real

There are many real values, which can be denoted in many styles:

3.1415927 or 31415927$_{10}$-7 or 0.31415927$_{10}$+1 or .31415927$_{10}$1
instead of the symbol `$_{10}$` you may also use `e : 31415927e-7`

`0.9 .9 9.0 100.0 0.0 1$_{10}$2 10$_{10}$10 1$_{10}$-10 1$_{10}$0 --`

The class of real values in the finite memory of a concrete computer is finite by necessity; it is an implementation dependent image of the mathematical concept “real number system”. The largest real value in a certain implementation can be obtained by the environmental enquiry `max real` and the smallest real value which can be usefully compared with `1.0` from `small real`. (See also 0.11).

Observe again that there is no sign preceding a real-denotation. Of course you may write:

`+1.0 -37$_{10}$-4 -31415927$_{10}$-7` etc.

but then the `+` and `-` preceding the real-denotation are monadic-operators applied to the value denoted.

### 0.2.4. char

There is a prescribed minimal set of graphics in which we find all (small) letters, the digits and some other tokens. The class of character values is at least this minimal set; specific implementations, however, may extend it.

A character-denotation consists of the character denoted between two quote-symbols:

`"a" "b" "c" --- --- --- "x" "y" "z"`
`"0" "I" "2" "3" "4" "5" "6" "7" "8" "9"`
`"." "'10" "," "(" ")" "+" "_" --- ---`

Specific character-denotations are:

`" " or "."` representing the space-symbol (see 0.4.3)

`""""` representing the quote-symbol itself (see 5.1.1.1)

### 0.2.5. `bool`, `int`, `real` and `char`

<table><tr><td>(D1)</td><td><pre>  loc bool p, q;<br>  loc int i, j, k, m, n;<br>  loc real a, b, x, y;<br>  loc char c;</pre></td><td><pre>bool p, q;<br>int i, j, k, m, n;<br>real a, b, x, y;<br>char c;</pre></td></tr></table>

In these declarations boolean variables are “ascribed” to the identifiers `p` and `q`; correspondingly integral variables are ascribed to `i`, `j`, `k`, `m` and `n`,
real variables to *a*, *b*, *x* and *y* and a character variable to *c*. That is to say
these identifiers are made to yield the names *p*, *q*, *î*, *j*, *k*, *m*, *n*, *â*, *b*, *x*,
*ŷ*, and *ĉ* referring to boolean-, integral-, real- or character-values
respectively. **loc bool**, **loc int**, **loc real** and **loc char** are "local generators"
and signify that the lifetime of the values generated is restricted. However,
since **loc** is the default situation, this symbol may be omitted here thus
preserving some similarity to ALGOL60.

In this Informal Introduction, identifiers will occasionally occur out of
context from their declarations. Unless otherwise specified, these identifiers
will be assumed to have been declared as listed in D1 (or D2, D3, --
hereafter). The complete set is listed in Appendix 2.

For boolean values operators are defined: `or`, `^` or `and`, `~` or `not`, yielding boolean values. Boolean values can be compared `=`, `≠` or `/=`; the result of a comparison is also a boolean value. The monadic-operator **abs**, however, when applied to a boolean value, yields an **int**: `abs p` is `1` if `p` is **true**, `abs p` is **0** if `p` is **false**. This can be expressed concisely as the conditional-clause (`p | 1 | 0`).

Many operators are defined for integral and real values: `+`, `-`, `x` or `*`, `/`, `÷`, or `%` or `over` (implying integral division), `mod` or `÷x` (for the modulo operation), `↑` or `**` (for raising to the power), etc. The result is an integral value when both operands are integral (except division which always yields a real value); in all other cases the result is real.

Integral and real values can be compared: `<`, `≤` or `<=`, `=`, `≠` or `/=`, `≥` or `>=`, `>`; the result is a boolean value.

The monadic operator **abs**, when applied to an **int** or a **real** *ir*, yields
(*ir* < 0 [ -*ir* | *ir* ).

The monadic operators **round** and **entier** (integral part of) serve to transfer
a **real** into an **int**. The transfer of an **int** into a **real** is implicit in the language
(no operator is needed to control this transfer); you may write:

x := i

but you must write:

i := round x or i := entier x

Each character value corresponds to an integral value; no two different
characters correspond to the same **int**; the actual correspondence is to be
defined by the implementation. The **int** corresponding to a **char** is obtained
by applying the monadic operator **abs** (*abs c* yields the integral value
corresponding to *c*), and the converse operation by **repr**.
Character values can be compared as if they were integral values and by
the same operators; in fact their **abs** values are then compared.

Character values are the materials from which **strings** are composed (see
Section 0.4.3).

## 0.3. Loops

Suppose we want to input many pairs of numbers x and y and we want to
do the algorithm E1 that many times. Let the input start with an integral
number greater than zero, which fixes the number of pairs following.
Then—in a very old-fashioned way—the program might be:

(E4)

**begin**
    loc int n; read (n); loc int count := n;
    loc real x, y;
    again:
        read ((x,y));
        print((x+y)/2 - sqrt(x*x));
        count := count - 1;
        if count > 0 then goto again fi
end

1. The reason we declared *n* was to hold the number of pairs; it is quite
natural to read this *n* immediately after its declaration. In this language it is
allowable to put statements between declarations. The counting will be done
via the identifier *count*; the counter is initialized at its very declaration.

3. The identifier *again* defines a 'label' signposting a point in the program where we want to go to from elsewhere. Labels are only allowed beyond the declarations (i.e. it is not allowed to write a label in a serial-clause where a declaration follows).

5. The counter is decreased by 1. Operations of this kind occur so often in
the practice of programming that we have got special operators for them;
they combine subtraction (or addition, multiplication, division etc.) with
assignation. We thus may write:

count minusab 1 or count - := 1

6. We may combine the phrases 5 and 6 into one, also omitting the
redundant go-to-symbol goto:

if ( count - := 1 ) > 0 then again fi

which can be abbreviated into:

((count - := 1) > 0 | again)
The use of labels and gotos leads in many cases to badly structured programs and should be avoided wherever it is possible. In this language we have alternative constructs to structure the program in such cases, avoiding the goto entirely.

In particular, a cycle like E4 can be put in a more concise form in which the counting will be done behind the screens. The result is a much safer and also more transparent program:

(E4*)

begin
    loc int n; read (n);
    to n
    do loc real x, y; read ((x, y));
    print ((x+y)/2 - sqrt (x * y));
od

end

1. Where the counting is done behind the screens we do not have to declare a *count*.

2. The serial-clause following, between *do* and *od*, will be repeated *n* times.

3, 4, 5. Between *do* and *od* we find a serial-clause, establishing a reach in which, consequently, variables of local scope can be generated (here ascribed to *x* and *y*). This construct *to n do ---- od* is a particular case of a much more general construction (see 0.6).

## 0.4. The creation of new modes, multiples

One of the interesting features of this language is the possibility of deriving new modes from the primitive ones, as many as you need. The method whereby new modes are created is such that they can, in their turn, be used to create further modes in a perfectly systematic manner. Some of these derived modes, such as *string* and *compl* (complex) are standard in the language (i.e. being declared in the standard-prelude, they are permanently built in).

In this section, we shall briefly outline the construction of multiple values (multiples). Other constructions (procedures, structures, references, unions and further derived modes) will be outlined in following sections. You will find a more systematic treatment in Chapters 1 and 2.

### 0.4.1. Multiples

Suppose you want to use a row of *n* reals named *u*, then you may declare, for instance:

(E5)

loc [1:n] real u; The lower-bound of the row is 1,
the upper-bound of the row is the value of *n*.
Now you have at your disposal *n* real values on the stack:

$u[1], u[2], \dots, u[n]$

In fact you have got more than this, you have got *n* "subnames":

$\hat{u}[1], \hat{u}[2], \dots, \hat{u}[n]$

to which you can assign new values as in the case of simple variables:

$u[i] := u[i] + x$

$u[i] := u[n-i]/u[j]$ etc.

If you want to use a square matrix of *n* x *n* reals (a row-row-of-real) named *a*, then you may declare, for instance:

(E6) $\mathbf{loc}[1:n, 1:n] \mathbf{real} a;$

Now you have at your disposal *n* x *n* real values on the stack:

$a[1,1], a[1,2], \dots, a[1,n], a[2,1], a[2,2], \dots, \dots, a[n,n]$

In fact you have got *n* x *n* subnames to which you can assign new real values:

$a[i,j] := a[i,k] \times a[k,j]$

$a[i,j] := a[j,i] / (i+j)$ etc.

(D2) $[1:n] \mathbf{real} x1, y1;$ [1:n] $\mathbf{int} i1;$ Observe how the optional
$[1:m,1:n] \mathbf{real} x2;$ [1:m,1:n] $\mathbf{int} i2;$ loc has been omitted as
$[1:n,1:n] \mathbf{real} y2;$ we shall often do in the
sequel

By E4 and E5 we declared the identifiers *u* and *a* to yield the names *û* and
*â* respectively (see also 0.1). The name *û* refers to a [ ] real, a row-of-real, the
name *â* refers to a [, ] real, a row-row-of-real. That is to say that *u* yields a
[ ] real variable and *a* yields a [, ] real variable in much the same way as, for
instance, *x* yields a real variable and *p* a bool variable.
<figure><img src="image_10.png" /></figure>

Now the question arises as to whether we may assign, for instance:

$u := x1$

$a := y2$

the answer is yes, and it does exactly what you should expect it to do:

$u[1] := x1[1], u[2] := x1[2], \dots, u[n] := x1[n]$

and:

$a[1,1] := y2[1,1], a[1,2] := y2[1,2], \dots, a[n,n] := y2[n,n]$

provided, of course, that the bounds to the left and to the right of the becomes-symbol are equal. Also an input-statement like:

`read (y2)`

does what you would expect:

`read ((y2[1,1], y2[1,2], \dots, y2[1,n], \dots, \dots \dots \dots, y2[n,n]))`
Where û is a name referring to the whole of the multiple value:

$u[1], u[2], \dots, u[n]$

the 'slice' $u[2:5]$ yields a subname referring to a part (a slice) of that multiple value, namely:

$(u[2], u[3], u[4], u[5])$

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

In much the same way $a[i, \, ]$ yields a subname referring to the multiple value:

$(a[i,1], a[i,2], \dots, a[i,n])$

Therefore, even assignations like:
$u[2:5] := x1[n-3:n];$

$a[i, ] := u;$

$a[i, ] := y2[,j]$

etc. do exactly what they suggest. For further discussion see 1.5.1 and
5.5.1.3.

Moreover, operators acting upon multiple values and slices may also be
defined (see, for example, 8.5), so that we can then write clauses like:

$u := x1 + y1;$

$a := y2 \times a$

### 0.4.2. New mode indications

Once you have decided to create a new mode, you may want to give this
new class of values a distinguishing mark (we do not say "name", because
that is a technical term in this language with a very specific meaning, see 0.1
and 0.8). You may define a new 'mode-indication' by declaring:

(E7) **mode vector** = [1: n] real ;

mode matrix = [1: n,1: n] real ;

And now, in the context of these mode-declarations:

(E5*) **loc vector** *u*; is equivalent to E5 : loc [1: *n*] real *u*;

(E6*) **loc matrix** *a*; is equivalent to E6 : loc [1:n,1:n] real *a*;

### 0.4.3. Multiples with flexible bounds, strings

In E5 and E6 the bounds of the variables (the lower-bounds *l*, and the
upper-bounds *n*) are fixed at the elaboration of the declaration and cannot be
changed afterwards, but on some occasions you might wish to do just that,
although this may be expensive in some implementations (the storage
allocation at run time is more complicated than in the case of fixed bounds).

Variables whose bounds may be changed after the declaration of the
multiple are termed "flexible" (flex):

(E8) **loc flex** [*m*: *n*] **real** *fu*; the bounds of *fu* are initially [*m*: *n*] but may be changed later.

Flexible bounds are particularly useful in the case of **strings**, which are
built into the standard-declarations of the language (which is why one may
expect a reasonably efficient implementation of, in particular, this flexible
bound application). A **string** is a row-of-character with flexible bounds:

(D3) **mode string** = flex [1: 0] char;
loc string s;
The variable-declaration **loc string** s (which is equivalent to **loc flex** [1:0] **char** s) declares s to yield a flexible name s referring to a row-of-character, which is empty to begin with. As soon as you assign to s, the bounds get the new values required:

$$
\begin{array}{l}
s := \text{"the upper-bound becomes 26";} \\
s := \text{"the flexible upper-bound now becomes 39";} \\
s := \text{""} \qquad \text{the string is empty again}
\end{array}
$$

By the way, you have just met three string-denotations, the lower-bound
of a string-denotation is always 1. Observe that the denotation for the empty
string is "", and for the space is " " (or may also be " _ ").

For **string**, being a built-in mode, several operators are defined, such as <,
≤, =, ∥, ≥, > (to compare them) and + and × (to concatenate them).

If the value of s is "this is the begin", then the outcome of the assignation:

(E10) $s := s + $ and this is the end.$

or (which is the same):

(E10*) $s += $ and this is the end.$

may speak for itself.

0.5. The value of a unit

So far we have met identifiers and denotations as the objects in this
language that yield a value of some mode. They are, however, only specific
cases of a ‘unit’. In this section we shall show you over some units and pay
some attention to the values they may yield. The complete and systematic
treatment will be found in Chapter 5.

0.5.1. The value of a formula

A formula is a unit. For example:

$$
x+y, (x+y)/2, (x+y)/2-sqrt(x*y)
$$

A formula defines a (more or less compound) computation, which usually
yields (i.e. delivers on the stack) a value of some mode. We then say: "the
formula yields (upon elaboration) the value".

In the example above, we met:

identifiers x and y, units yielding variables,
a denotation 2, a unit yielding a constant;

and another kind of unit sqrt (x × y), which is the 'call' of a procedure
returning a value: the square root of the value of the formula x × y (for
procedure calls see Section 0.7).

Different operators may have different priorities. The implied bracketing
in the example above is:

$$ \frac{(x+y)}{2} - \sqrt{\overline{x \times y}} $$

left-operand right-operand

The 'left-operand' and the 'right-operand' of the subtraction are elaborated
collaterally. That is to say that there is no prescribed order for getting the
value of the left-operand and getting the value of the right-operand (see also
0.1). The same applies again to the elaboration of the left- and the
right-operand in the formula $(x+y)/2$.

Hence, an implementor is perfectly entitled to optimize the elaboration of
formulae. For example:

$$ y1[\text{round sqrt}(a \times b)] + i1[\text{round sqrt}(a \times b)] \times x1[\text{round sqrt}(a \times b)] $$

The implementor may elaborate `round sqrt (a x b)` only once (for reasons
explained in 3.7.1), and elaborate the multiplication `i1 [k] x x1 [k]` before
accessing `y1 [k]`; that is to say that there is no prescribed order of elaboration
"from left to right".

### 0.5.2. The value of a conditional clause

A conditional-clause is a unit:

if $p$ then $31415927_{10}-7$ else $27182818_{10}-7$ fi

yields upon elaboration the **real** value of its then-part or of its else-part,
depending upon the value of its condition. You may assign it to a **real**
variable, or use it in a formula:

$$ x := 1 / (p | 31415927_{10}-7 | 27182818_{10}-7) $$

If a conditional-clause yields a variable then you are perfectly entitled to
use it in a destination (to the left of a becomes-symbol):

if $p$ then $x$ else $y$ fi := 3.1415927

or:

$(p|x|y) := 3.1415927$
### 0.5.3. The value of a serial clause

A serial-clause (see 0.1) may also yield a value, although it is not (yet) a unit. It may be used, however, to make a unit. For example, a closed-clause, which is a unit (see 0.5.4), contains a serial-clause, and a conditional-clause (another unit) may contain several of them.

The value of a serial-clause, then, is the value of its final (completing) unit.
The serial-clause:

```
read (x); x ≠ 0
```

(see E11 below) yields the value of its final unit $x ≠ 0$, which is a **bool** value.
Now consider the program:

(E11)

**begin**
    int num := 0, pos := 0, neg := 0, real absum := 0, x;
    while read (x); x ≠ 0
        do absum plusab if num +:= 1; x > 0
            then pos +:= 1; +x
            else neg +:= 1; -x
        fi
end

```
od;
print((num, pos, neg, absum))
end
```

Here we meet another form of a loop-clause (see 0.3 E4). In a loop of the form:

```
while C do S od
```

first of all the condition C will be elaborated, yielding a **bool** value; as long as this condition yields **true**, the serial-clause S between **do** and **od** will be elaborated, followed by a new elaboration of C. That is to say: depending on the **bool** lastly yielded by C, the elaboration of **while C do S od** results in

C or C;S;C or C;S;C;S;C or C;S;C;S;C;S;C etc.

3. Now, in E11 above, the construct after **while** is the serial-clause

```
read (x); x ≠ 0
```

yielding the **bool** value yielded by its last unit $x ≠ 0$. Hence, if the first number read is 0, the clause between **do** and **od** will never be elaborated; if, on the contrary, this number is unequal to 0, then the formula
4-7. absum plusab if num +:= 1 ; x > 0
then pos +:= 1 ; +x
else neg +:= 1 ; -x
fi

will be elaborated.

The right operand of plusab is a conditional-clause, the condition of which is a serial-clause increasing the counter num by 1 and yielding the bool value x > 0. Depending on this condition the then-part pos +:= 1 ; +x or the else-part neg +:= 1 ; -x will be elaborated, yielding either +x or -x after having increased either pos or neg by 1. That is to say: the serial-clause between do and od (here a formula) results in adding abs x to absum.

3. After that the serial-clause after while is revisited, repeating the story (looping the clause) as long as the number read is found to be unequal to 0.

It may happen that a serial-clause does not yield a value, because its final unit does not leave a value on the stack (the root of this will be shown in 0.7). We then say: "this serial-clause yields void". For example:

real x, y, z; read((x,y)); print(z:=(x+y)/2-sqrt(xtimesy))

yields void, because the output statement print (although it delivers humanly
recognizable graphics on some printing device) does not leave a value on the
stack. If, however, we want this serial-clause to yield, for example, the name
of the value printed (from which that value may then be obtained), then we
simply make z its final unit:

real x, y, z; read((x,y)); print(z:=(x+y)/2-sqrt(xtimesy)); z

0.5.4. The value of a closed clause

A closed-clause (see 0.1) is a unit and as such it may be used in formulae
and in assignations. The value of a closed-clause is that of its constituent
serial-clause:

x2[i, j] := ( real x, y, z; read((x,y));
             print(z:=(x + y)/2 - sqrt(x times y));
             z)

The value of a closed-clause may also be a name, and then you are entitled
to use it in a destination (see also 0.5.2); provided, of course, that the name
yielded does not happen to be local to the clause:

( real x, y, z; read((x,y));
  print(z:=(x + y)/2 - sqrt(x times y));
  if z > 1 then m else n fi) +:= 1
Under certain circumstances it may be annoying to have to arrange a closed-clause in such a way as to deliver the value required, because there may be more than one candidate for the final unit. In such cases a 'completer' may help. A completer is the symbol **exit**; the unit preceding a completer is (by definition) a completing (final) unit of the closed-clause. You may take a completer as a suppositious close-symbol.

For example, suppose you want a closed-clause to read a block of *n* pairs of real numbers and to deliver **false** if there is no pair in the block in which the difference between the arithmetic and geometric mean is greater than 1, but to deliver **true** and to print the first such pair if this is the case. This may be programmed as follows:

(E12) $p := (\text{real } x, y, z;$
       to $n$ do read((x,y)); z := (x+y)/2-sqrt(x*x);
       if $z > 1$ then finish fi
       od;
       false exit
       finish: print((x,y));
       true)

(For another example in which a completer is used, see E28* in 0.7.3).

### 0.5.5. The value of a constant

To conclude this bird's-eye view, we consider an extremely simple kind of unit, the constant. You may declare:

(E13) real $pi$ = 3.1415927

The thus declared identifier $pi$ yields a real value (and not a real variable), in much the same way as the denotation 3.1415927 yields that value. You cannot assign to $pi$ (it not being a variable): $pi := 2.7182818$ would be as nonsensical as is 3.1415927 := 2.7182818. Beware of the slight notational distinction between E12 and:

(E13*) real $pivar$ := 3.1415927

This distinction would have been clearer if we had written:

(E13**) loc real $pivar$ := 3.1415927

To $pivar$ you may assign any other real value ($pivar$ being a real variable). For the notational matter, see 0.8.
Declarations of constants enable the programmer to enforce efficient
compilation, for example in accessing the elements of multiple values.
Compare E14 and E14* below:

$$
\begin{align*}
\text{(E14)} \quad \begin{array}{lcl} \mathit{sw} & \mathop{\cdot} & \mathit{w}[i]; \\ \mathit{swx} & \mathop{\cdot} & \mathit{w}[i] \times \mathit{x}[i]; \\ \mathit{swx2} & \mathop{\cdot} & \mathit{w}[i] \times \mathit{x}[i] \times \mathit{x}[i]; \\ \mathit{swx3} & \mathop{\cdot} & \mathit{w}[i] \times \mathit{x}[i] \times \mathit{x}[i] \times \mathit{x}[i] \end{array}
\end{align*}
$$

In E14 an element such as w[i] and x[i] has to be pulled many times out
of a multiple value, which may be rather time consuming.

$$
\begin{array}{l@{\quad}l@{\quad}l}
\text{(E14*)} & \mathbf{real} & \mathit{wi} = \mathit{w}[i], \mathit{xi} = \mathit{x}[i] ; \mathbf{real} \ \mathit{wixi} = \mathit{wi} \times \mathit{xi} ; \mathbf{real} \ \mathit{wixi2} = \mathit{wixi} \times \mathit{xi} ; \\
& \mathit{sw} & \mathop{\cdot} \mathit{wi} ; \\
& \mathit{swx} & \mathop{\cdot} \mathit{wixi} ; \\
& \mathit{swx2} & \mathop{\cdot} \mathit{wixi2} ; \\
& \mathit{swx3} & \mathop{\cdot} \mathit{wixi2} \times \mathit{xi} ) & \quad \text{(see also E15)}
\end{array}
$$

In E14*, an element is never taken out of a multiple more than once. Of
course, you could have achieved most of this efficiency equally well by
declaring the proper local variables: **real wi** := *w[i]*, *xi* := *x[i]*; etc, but then
you would still have to go via the names when getting the values referred to
(which may take longer in some implementations). In the form of a constant,
you have the desired values most readily at hand.

The importance of the declaration of constants, however, is to be found at
another level; in Chapter 1, we shall see that in all identity-declarations a
constant is declared (see also 0.7 and 0.8), and this mechanism is nothing
more nor less than the life-line of the formal – actual correspondence.

0.6. A more involved program

Before embarking upon routines and other new modes that actually make
the new language, it is worthwhile to dwell on the subject of primitive
declarations and multiple values for just one section more. Many of the (until
now only) newly dressed features of the language will be found in full swing
in the more involved example E15 below. Although it is the program that
matters here, it may acquire a not too artificial setting in the following
context:

Suppose the input starts with an integral number *n*, which fixes the
number of pairs of measurements following. The first **real f** of each pair is a
factor, accounting for environmental influences on the target measurement,
which is the second **real x** of the pair. There may be other (not measured)
influences on $x$, which is why we are not particularly interested in the correlation of the two. We therefore confine ourselves to the computation of the mean, dispersion and momental skewness of the $x$'s, weighted by the (more or less normal) distribution of the $f$'s. Preceding the $(f,x)$-couples, but following $n$, we input another pair of *reals* $\epsilon$s and *ups*; all $x$'s below $\epsilon$s or above *ups* are to be discarded as being certainly out of range (as a result of punching errors, for instance).

We briefly survey the program E15 (the numbers in the margin refer, as usual, to the line numbers in the program text):

1---. In any place in a program text (except within identifiers and denotations) comments may be inserted. A comment begins and ends with the comment-symbol **comment**. Alternatively **co**, **c** or **#** can be used in matched pairs:

c this was the beginning of a comment and this is the end:c

3, 9, 24-25 **for** *i* to *n* **do** (as well as **for** *i* to *n* while **C** **do** etc.) are specific cases of the general construction of a loop-clause:

**for** *i* **from** *start* **by** *step* **to** *finish* **while** *condition* **do** *clause* *od*

The integral counter *i* is implicitly local to the construction (it has nothing to do with a possibly declared other *i*). If the counter *i* does not occur in the *clause* or in the condition, then you may omit **for** *i*. If *start* is *1*, you may omit **from** *start*. If *step* is *1*, you may omit **by** *step*. If you do not want to finish at a certain value of *i*, you may omit **to** *finish* (see also E11 *). If it is **true**, you may omit **while** *condition*.

11-13 The construction : or, in the abbreviated notation:

<table><tr><td>if C1 then C1true</td><td>( C1 | C1true</td></tr><tr><td>elif C2 then C2true</td><td>|: C2 | C2true</td></tr><tr><td>elif C3 then C3true</td><td>|: C3 | C3true</td></tr><tr><td>else C3false</td><td>| C3false</td></tr><tr><td>fi</td><td>)</td></tr></table>

is shorthand for the nested conditional-clauses:

<table><tr><td>if C1 then C1true</td><td></td></tr><tr><td>else if C2 then C2true</td><td></td></tr><tr><td>else if C3 then C3true</td><td></td></tr><tr><td>else C3false</td><td></td></tr><tr><td>fi</td><td></td></tr><tr><td>fi</td><td></td></tr><tr><td>fi</td><td></td></tr></table>
38-46. The statement *print* is a very accommodating output carrier. It accepts almost everything you may invent to output,

be it a lay-out procedure like: `new line` ,

or a **string** denotation like: `"number of measurements: "` ,

or a variable like: `n`, `below`, `above` ,

or a unit like: `sqrt (varf)` ,

or a row-display of them all.

1-46. In the example E15 we are very strict about the use of variables and constants: we never use a variable when a constant suffices (i.e. when we do not assign to it). Of course, you could declare all identifiers to yield variables; in some implementations, however, a constant might be slightly more efficient. Pay also some attention to the use of and-also-symbols (collateral elaboration of declaration and row-displays) and go-on-symbols (serial elaboration).

(E15) **begin**

1) **int** `n`; `read (n);` `¢ number of measurements ¢`

2) **real** `eps`, `ups`; `read ((eps, ups))`; `¢ eps ≤ x[i] ≤ ups ¢`

3) `[l:n]real f, x`; **for** `i` **to** `n`

4) `do read ((¢factor¢ f[i], ¢measurement¢ x[i])) od;`

5) **int** `below := 0`, `¢ number of measurements rejected: too small ¢`

6) `above := 0`, `¢ number of measurements rejected: too large ¢`

7) **real** `sf := 0`, `¢ sum factors accepted ¢`

8) `sf2 := 0`; `¢ sum squared factors accepted ¢`

9) **for** `i` **to** `n`

10) **do** `real xi = x[i]`;

11) `sf += if xi < eps then below += 1; f[i] := 0`

12) `elif xi ≤ ups then f[i]`

13) `else above += 1; f[i] := 0`

14) `fi`;

15) `sf2 += f[i]↑2`

16) **od;**

17) **int** `m = n - below - above;`

18) **real** `af = sf/m`, `¢ mean factor ¢`

19) `varf = sf2/m - af × af`; `¢ variance of the factors ¢`

20) **real** `sw := 0`, `¢ total weight ¢`

21) `swx := 0`, `¢ sum weighted measurements ¢`

22) `swx2 := 0`, `¢ sum squared weighted measurements ¢`

23) `swx3 := 0`; `¢ sum cubed weighted measurements ¢`
24) for i to n

25) while real $fi = f[i]$; $fi \neq 0$

26) do real $xi = x[i]$, $wi = \exp(-(fi-af)^2)/(2 \times varf)$;

27) real $wixi$, $wixi2$;

28) $sw +:= wi$;

29) $swx +:= (wixi := wi \times xi)$;

30) $swx2 +:= (wixi2 := wixi \times xi)$;

31) $swx3 +:= wixi2 \times xi$

32) od;

33) $\zeta$ first , second , third moment about 0 $\zeta$

34) real $ax = swx/w$, $ax2 = swx2/w$, $ax3 = swx3/w$;

35) real $varx = ax2 - ax \uparrow 2$;

36) real $sdx = sqrt(varx)$;

37) real $skx = (ax3 - 3 \times ax \times ax2 + 2 \times ax \uparrow 3)/(2 \times varx \times sdx)$;

38) print((newline,

39) "number of measurements:" , $n$ , "below:" , $\underline{\underline{\text{below}}}$ , "above:" , $\overline{\overline{\text{above}}}$ ,

40) newline,

41) newline,

42) "mean factor:" , $af$ , "dispersion:" , $\sqrt{varf}$,

43) newline,

44) newline,

45) "normal mean:" , $ax$ , "dispersion:" , $sdx$ , "skewness:" , $skx$

46) })

end

## 0.7. Routines and procedures

A concept of fundamental importance in programming is the "routine", a unit that can be activated from different places in the program, under different circumstances and in different incarnations when elaborated recursively. Moreover, routines may have a provision for formal-parameters, to which the actual-parameters are then supplied when the routine is activated.

Routines, and also their names, may be ascribed to identifiers; we then speak about 'procedures'. In this language, a routine may also be ascribed to an operator. Procedures and operators are to be distinguished in that they are activated differently. Procedures are activated by "calling" them, and operators by applying them in formulae. In this section we shall consider procedures; for operators see 0.10.
### 0.7.1. Procedures without parameters

With the aid of the symbol **proc** we can derive new modes from already defined ones (as we did with the aid of the symbols [ and ] in 0.4). We thus obtain one of many possible **proc** modes, the simplest of which is the **proc void** (without parameters, not returning any value).

Suppose we want to turn the algorithm E1* into a procedure. This algorithm is defined by a unit (a closed-clause); we declare it as a **proc void** in the following way:

$$ (E16) \quad \textbf{proc } p = \textbf{void:} \quad (\textbf{real } x, y, z; \textbf{read}((x, y))); \quad \textbf{print} (z := (x + y)/2 - \sqrt{x \times y}); $$

The right hand side of this identity-declaration is a routine-text. It yields a corresponding routine - a value of mode **proc void** - which is now ascribed to the identifier *p*. The unit to the right of **void**: is not, of course, elaborated at this stage.

The procedure *p* does something for you: it reads two numbers, does some computation with them and finally prints the result. However, it does not, and it cannot, return any value; *p* is declared to be a procedure returning **void**.

For those who are accustomed to the "procedure body" (a well known concept in some other programming languages), the alternative writing:

$$ (E16*) \quad \textbf{proc } p = \textbf{void:} \quad \begin{array}{l} \textbf{begin} \\ \quad \textbf{real } x, y, z; \\ \quad \textbf{read}((x, y))); \\ \quad \textbf{print} (z := (x + y)/2 - \sqrt{x \times y}); \\ \quad \textbf{end}; \end{array} $$

may be more familiar.

Within the context of the declaration E16, we can call this procedure. Consider:

(E17) **begin** int *n*; read(*n*); **to** *n* **do** *p* **od** end

Between **do** and **od** we find *p*. By virtue of its declaration, *p* is a unit of the mode **proc void**. The elaboration of a unit of the mode **proc void** is (in this syntactic position) the elaboration of its unit. Therefore, the piece of program above is, at least in its effect, equivalent to E4 (see 0.3).

We often want a procedure to return a value. For example, *p* could do just a little more and return the value printed. Inside the closed-clause this value is referred to by *z*. We already know how to get a closed-clause to yield a
specific value (0.5.4). Now, by prefacing it with **real**: , we arrive at the
declaration of a **proc real**:

$$
\begin{array}{l}
\text{(E18) \quad proc } pz = \text{real:} \ (\text{real } x, y, z; \ read\ ( (x, y) ); \\
\qquad \qquad \qquad \quad \text{print}\ (z := (x + y)/2 - sqrt\ (x \times y)); \\
\qquad \qquad \qquad \quad z);
\end{array}
$$

The mode **proc real** is derived from **real** as, for instance, was [*I:n*] **real**.

Within the context of E19, it is not difficult to understand the effect of
the following piece of program:

(E19) **begin**
    **int** n; read (n);
    **int** less := 0, morequal := 0;
    **to n** **do** (print (newline); pz < 1 | less | morequal) +:= 1 **od**;
    print ((newline, newline, less, morequal))
**end**

The *pz* in the formula *pz* < 1 is a unit of the mode *proc real*. The elaboration of a *proc real* unit is (in this syntactic position) the elaboration of the routine it yields; that routine returns a *real* value, and consequently *pz* yields that *real* value.

0.7.2. Procedures with parameters

Even more important than procedures without, are procedures with
formal-parameters. The actual-parameters are then supplied when the
procedure is called, as we have already done on several occasions when calling
the standard procedures *read*, *print* and *sqrt*.

We now declare a procedure *d* with two *real* parameters returning a *real* value, a *proc* (*real*, *real*) *real*:

(E20) proc d = ( real a, b ) real: (a + b)/2 - sqrt (a x b) ;
| 1 || 2 |
| :--: | :--: |
|   3 |  . |

1. These are the formal-parameters *a* and *b* which are both specified to be of mode **real**. The actual-parameters have to match this mode. There are, however, certain facilities in this respect. If, for instance, a **ref real** is supplied, then its **real** value will be taken; if an **int** is supplied, then it will be "widened" into a **real**.

2. The prefix **real**: requires that the routine is to return a **real** value, when called.
3. The whole sequence of symbols to the right of the = is a 'routine-text'. It yields a routine, which requires two real parameters. The elaboration of a call in which actual-parameters are then supplied to match these formal- parameters, is the subject matter of 1.2.3 and 4.2.2.2. It will suffice, here, to state that a and b, as formally declared in our example E20, will be real constants in the routine (when, for instance, x and y are supplied as actual-parameters, then the identity-declarations real a = x, b = y; will be elaborated). That is to say, the actual-parameters are elaborated once, to supply their real values. In other programming languages this phenomenon may be known as "call by value" (see also 0.8.2 and 0.8.3).

Within the context of the declaration E20, the algorithm E1, for example, could be programmed in the following way:

(E21) begin real x, y, z; read (x, y);
        print (z := d(x, y)) end

The assignation E12 (see 0.5.4) could look like:

(E12*) p := (real x, y, z;
          to n do read (x, y);
          if d(x, y) > 1 then finish fi
          od;
          false exit
          finish : print (x, y);
          true
        )

An example of a procedure with a parameter but not returning a value is:

(E22) proc skip = (int n) void:
        ( real x; to n do read (x) od );

which skips n numbers on the input tape.

### 0.7.3. Examples of procedure declarations

We have four kinds of procedures:

1) without parameters, not returning any value;

2) without parameters, returning a value;

3) with parameters, not returning any value;

4) with parameters, returning a value.
Examples:

proc skiptozero = void: ( loc real x := 1 ;
                      while x ≠ 0 do read (x) od )

¢ which was a proc void ¢ ;

proc nexttozero = real: ( skiptozero ;
                          loc real x ; read (x) ; x )

¢ which was a proc real ¢ ;

proc skipto = ( real a ) void: ( loc real x := a − 1 ;
                                     while x ≠ a do read (x) od )

¢ which was a proc ( real ) void ¢ ;

proc nextto = (real a) real: ( skipto (a) ;
                                loc real x ; read (x) ; x )

¢ which was a proc( real ) real ¢ ;

In the standard prelude of the language, we find declarations for the proc
(real) reals sqrt, exp, ln (the natural logarithm), cos, arccos, sin, arcsin,
tan, arctan. Moreover there is a proc real random, which returns the next
pseudo-random real value from a uniformly distributed sequence on the
interval [0,1) (i.e. 0 ≤ random < 1). Finally we find in the standard prelude
an identity-declaration real pi = c a real value close to π c. (See 1.3.2 for the
significance of the special comment-symbol c).
To these we subjoin:

To these we subjoin:

(D4) proc ncos = (int i) real: cos ( 2 × pi × i/n ) ; ¢ a proc ( int ) real ¢
proc nsin = (int i) real: sin ( 2 × pi × i/n ) ; ¢ a proc ( int ) real ¢
real e = c a real value close to the base of natural logarithms,
i.e. 2.718281828459045 c ;

Another example of a proc/int/real declaration is:

(E23) proc fac = (int n) real:
    if n > nmaxfac
    then faclarge (n)
    else int f := 1;
        for i from 2 to n do f x:= i od; f
    fi;

where *nmaxfac* is an implementation dependent integral constant which is
related to *maxint* in the following way:

(E23*) int nmaxfac = (int n, f := 1;
                  for i while f ≤ maxint ÷ i do n := i; f × n := n od; n);

and faclarge is another proc/int/real:
(E23**) `proc faclarge` = (`int n`) `real`:

c depending on `nmaxfac`:

stirlings formula with correction factor,

sqrt((2 * pi * n) / (n/e)) * n / corr(n)

or some series expansion for 1/gamma(n);

see "Handbook of Mathematical Functions"

edited by Milton Abramowitz and I. E. Stegun

Sections 6.1.37/38 and 6.1.34 c;

The `proc/int/real fac`, as declared in E23, attempts to return the exact real equivalent of `n!` as long as this value remains ≤ `maxint` (the critical value of `n` is yielded by the constant `nmaxfac`); otherwise, a `proc/int/real faclarge` is called to give a reasonable approximation.

Formal-parameters may be of any mode and procedures may return a value of any mode. The time has not yet come for the more arresting examples, which is why we confine ourselves to two simple ones. Both of them will put in another appearance in 0.8.2, because their efficiency can be improved. The starred example numbers refer to the unstarred numbers in Section 0.8.2.

(E27*) `proc maxindex` = ([ ] real `a`) `int`:

( `int j` := `lwb a`

for `i` from `j` + 1 to `upb a`

do if `a[i]` > `a[j]` then `j` := `i` `fi od; j`;

In E27* we see the declaration of a procedure with a 'row of real' parameter, returning an `int`, a `proc([] real)/int`; `maxindex` returns the index of the maximal element in a given row (if there are more "maximal elements", then the lowest of their indices is returned).

The monadic-operators `upb` and `lwb` return the values of the upper-bound and lower-bound respectively; being declared in the standard-prelude of the language, they are permanently built in and are applicable to all kinds of multiples. If the multiple has several subscripts, they are dyadic-operators (so that, for instance, `2 upb x2` returns the second upper-bound of the row-row-of-real `x2`).

The `proc(char string/bool match`, declared below, returns `true` if the character ascribed to the formal-parameter `c` occurs in the given `string`; if not, then the value returned by `match` will be `false`. In this procedure we make use of a completer (see 0.5.4):

(E28*) `proc match` = ( char `c`, string `s`) `bool`:

( for `i` from `lwb s` to `upb s`

do if `c` = `s[i]` then `yes` `fi od`; `no`: `false` exit

`yes`: `true`);
## 0.8. The creation of new modes, names and values referred to

### 0.8.1. Variable declarations revisited

It is time to reconsider the variable-declaration:

(E24) `loc real x;`

because it is not so innocent as it looks.

You might already have suspected this, knowing what its elaboration achieves (see 0.1):

a location for a real value is reserved in the memory of our computer (on the stack);

this real value is referred to by a name x̄ (i.e. its address);

this name x̄ is now ascribed to the identifier x.

In the program text, the identifier x thus represents a real variable, which is a real value associated with the name referring to it. What is "variable", of course, is not the name (the location, the address) but the value referred to. The name cannot be changed by the program, it has been ascribed to x and this relation is an indissoluble alliance. Nevertheless, a "name" is a value as well, and consequently it must have a mode. The mode, then, of the name x̄ is ref real ('reference to real').

The symbol ref plays a role in declarations as do the symbols [ and ] and proc (and some others which we shall meet soon): they assist in the creation of new modes. We now come to the unmasking of E24. Consider the identity-declaration:

(E24*) `ref real x = loc real;`

which expresses more precisely what happens during the elaboration of E24:

1) `loc real` is a `loc` generator which yields a `ref real`

2) this `ref real` value is ascribed to the identifier x.

Thus the effect of E24* is the same as that of E24 and, indeed, every variable-declaration has an equivalent identity-declaration hiding behind it.

The point to remember is the hidden fact that, on declaring a real variable, two values are involved:

1) a real which is variable.

2) a ref real which is constantly yielded by the identifier,

Getting ahead of Section 1.2.2.3 we may depict a variable-declaration happening as follows:
<figure><img src="image_12.png" /></figure>

which is the same as the situation depicted in 0.1. For a more systematic treatment see Chapter 1.

The result of the declarations E13 and E13* (see 0.5.5) can be depicted as follows:

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

To *pi* no other value can be assigned, *pi* being a constant.

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

To *pivar* any other value can be assigned, *pivar* being a variable.

Finally, we give some declarations in their three equivalent forms. The first indicates most clearly what is actually happening, although in practice one will always use one of the others (which are also more similar to declarations in other programming languages).

identity-declaration :

ref bool p = loc bool ;

ref int n = loc int ;

ref real x = loc real ,
y = loc real ;

ref char c = loc char ;

ref [ ] real x1 = loc [1: n] real ;

variable-declaration :

loc bool p ;

loc int n ;

loc real x , y ;

loc char c ;

loc [1: n] real x1 ;

bool p ;

int n ;

real x , y ;

char c ;

[1: n] real x1 ;
### 0.8.2. Procedures, values and references

One of the implications of the extremely fruitful concept of a reference ("name") as a value in this language is that we have been given a quite natural way of declaring (amongst many other very useful constructions):

I variable procedures,

II formal-parameters which refer to, rather than yield, the values which are topical ("actual") when the procedure will be called,

III procedures returning a name (a reference to a value).

We discuss briefly these three applications of the concept of a name by giving some examples.

I)

By declaring:

(E25) $\mathbf{mode fun = proc ( real ) real ;}$
$\mathbf{loc fun f ;}$

the identifier $f$ is declared to be a variable **fun** (to yield the name referring to a routine of the mode **proc(real)/real**).

Within the context of this declaration, we may assign any **fun** routine to this **fun** variable. For example:

$$f := \ln$$

Now the call:

$$y := f(x) \quad \text{is the call} \quad y := \ln(x)$$

while after the assignation:

$$f := (\mathbf{real} \ a) \ \mathbf{real} : a \times \ln(a) - a$$

the same call becomes:

$$y := x \times \ln(x) - x$$

II)

Even more important is the specification of a formal-parameter to be a name:

(E26) $\mathbf{proc read fun} = (\mathbf{ref real} \ a) \ \mathbf{real} : (\mathbf{read}(a); a := f(a));$

E26 declares the formal-parameter to be a **ref real** (the name of a **real**) to which, consequently, a **real** value can be assigned. This happens two times in the procedure: first the value of the number read is assigned to $a$ (by the call
of the procedure *read*), and then the *f* of that value is assigned to *a*. If we now
call this procedure, for example:

`y := read fun(x)--y`

then the formal – actual correspondence results in:

`ref real a = x;`

i.e. the formal name â is made to refer to the same real value as the actual
name û. The call *read fun(x)* thus results in assigning to *x* the *f* of the value
read. Which *fun* is then applied depends (in the context of E25) on the *fun*
assigned to *f*.

In other programming languages, a **ref** parameter may be known as an
"output parameter". In contradistinction to the more or less domesticated
term "call by value" in ALGOL 60 (see 0.7.2), this could be termed "call by
reference". For an equivalent of the ALGOL 60 term "call by name" see
0.8.3.

We are now in a position to improve on the examples at the end of 0.7.3.
There, the value parameters imply that a copy of the actual rows is to be
passed to the routine. Unfortunately, not all implementors have been able to
avoid actually making this copy. We now show how to avoid the problem
altogether.

(E27) proc maxindex = ( ref [] real a) int :
( int j := lwb a;
for i from j + 1 to upb a
do if a[i] > a[j] then j := i fi od;
j );

Now, in the call *maxindex(x1)*, only the name û1 is given to the
procedure: **ref [] real a = x1**. The access to the **[] real** referred to by û1 thus
runs via the formal name â to that very **[] real** and not (as was the case in
0.7.3) to a copy of it.

(E28) proc match = ( char c , ref string s ) bool:
( for i from lwb s to upb s
  do if c = s[i] then yes fi ; no : false exit
  yes: true );

Now, in the call *match('??', text)*, in the context of the declaration **string text**, the character `??` is copied onto the stack, but the name *text* is given to the procedure instead of a copy of its value.
### III)

An example of a procedure returning a name is:

(D5) `proc xory = ref real: if random < 0.5 then x else y fi;`

If we now assign:

`xory := 3.1415927`

then it depends on the value returned by `random` to what destination we actually assigned.

A more substantial example is:

(E29) `proc maxelmnt = (ref [] real a) ref real: (int j := lwb a; for i from j + 1 to upb a do if a[i] > a[j] then j := i fi od; a[j]);`

Compare E29 with E27. In E29, `â[j]` is a name referring to a maximal element of the actual row, when the procedure is called. If you want to assign a new value to the maximal element of, for instance, the row `x1`, then you could do it by a call of `maxindex`:

`x1 [maxindex (x1)] := y`

but also, and more directly, by a call of `maxelmnt`:

`maxelmnt (x1) := y`

### 0.8.3. Procedures as formal parameters

Compare:

(E30) `proc choice1 = ( real a) void: (a < 0.5 | x | y) +:= a; choice1 (random);`

with:

(E31) `proc choice2 = (proc real a) void: (a < 0.5 | x | y) +:= a; choice2 (random);`

In the call `choice1 (random)`, the identity-declaration `real a = random` will be elaborated. Hence, the `proc real random` is called only once and its value (`<0.5` or `≥0.5`) is added to `x` or to `y`.
In the call `choice2 (random)`, the identity-declaration `proc real a = random` will be elaborated. Hence, the `proc real random` is ascribed to `a` inside the routine and will be called once in the conditional-clause and again as the right operand of the `+:=` (i.e. `random` will be called twice in E31).

The construction E31 is similar to what in ALGOL 60 is known as "call by name"; it has, nevertheless, nothing to do with the concept of a name in ALGOL 68 (in which it is an application of the principle that any mode may occur in a formal-parameter, in particular also a `proc real`).

Compare also:

(E30*) `choice1 (x - y + ncos(k))`

and:

(E31*) `choice2 ( real: x - y + ncos(k))` `¢` see D4 in 0.7.3 `¢`

In E30*, the formula `x - y + ncos(k)` will be elaborated once in the elaboration of the identity-declaration `real a = x - y + ncos(k)`. Depending on the condition, this value (inside the routine ascribed to `a`) will be added to `x` or to `y`, so that the result of the call will be:

`x +:= a` i.e. `x +:= ¢` the value of `¢ x - y + ncos(k)`

or

`y +:= a` i.e. `y +:= ¢` the value of `¢ x - y + ncos(k)`

In E31*, on the contrary, the formula `x - y + ncos(k)` appears in a routine-text (the mode of which is `proc real`) and it is the routine yielded by `real: x - y + ncos(k)` which is ascribed to the `proc real` identifier `a` at the elaboration of the procedure-call. Hence, the formula will be elaborated twice (once in the conditional-clause and again as the right operand of the `+:=`). The two successive elaborations, however, yield the same value, which is why the two calls E30* and E31* have the same result (though E30* is the more efficient one).

However, compare now:

(E30**) `choice1 (x - y + ncos(k +:= 1))`

and:

(E31**) `choice2 ( real: x - y + ncos (k +:= 1))`

Each elaboration of the formula `x - y + ncos(k +:= 1)` has a side effect on `k` (`k := k + 1`) and therefore the two calls will not have the same result; in E30** the formula being elaborated once, and in E31** twice.
Another construction in which we find a procedure as formal-parameter
(in ALGOL 60 circles known as “Jensen’s device”) is:

$$
\text{(E32)} \quad \texttt{proc sigma = (int a, b, proc(int)real fun) real :} \\
\phantom{\text{(E32)} \quad \texttt{proc sigma = (int a, b, proc(int)real fun) real :} \\
\phantom{\text{(E32)} \quad \texttt{proc sigma = (int a, b, proc(int)real fun) real :} \\
\phantom{\text{(E32)} \quad \texttt{proc sigma = (int a, b, proc(int)real fun) real :} \\
\texttt{ ( real value := 0 ; } \\
\texttt{ for i from a to b do value +:= fun(i) od ; } \\
\texttt{ value ) ; }
$$

calls of which may be:

`y := sigma ( 1, n, (int j) real: x1 [j] );`

`y := sigma ( -m, +m, ncos );`

It is worth your while to find out why we have to give the **proc(int)real**
routine-text **(int j/real: x1 [j]** as actual-parameter in the first call, and why
ncos would do in the second call.

0.8.4. Pointers (variable names)

Until now, names have always appeared as being constantly yielded by
identifiers. By:

`loc real x;`

or:

`ref real x = loc real ;`

we declared *x* to yield constantly a **ref real** (the name of a **real**). Only the **real** value referred to could be changed and never the name *x*.

You may, however, also want to declare identifiers to yield variable names,
i.e. references to names. It may be clear immediately that such an identifier
will then yield a reference-to-reference. We thus declare:

(D6) **ref real xx, yy;**

or equivalently

(D6*)

**ref ref real xx = loc ref real,**

`yy = loc ref real;`

This collateral-declaration generates on the stack two **ref reals** (two
locations for names of reals), which simply means that via such values on the
stack you can refer to other values (reals):
<figure><img src="image_15.png" /></figure>

Consider now:

$$ (E33) \quad xx := y $$

After this assignment, the value of $xx$ (i.e. the **ref real** referred to by $x\bar{x}$) is the name $\hat{y}$ (i.e. the **ref real** yielded by $y$):

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

Observe that an assignment always takes place at the highest level possible.

Now the call:

$$ y := sqrt(xx) $$

results in: $y := sqrt(y)$, while after the assignment:

$$ (E33*) \quad xx := x $$
the same call results in

$$y := sqrt(x)$$

In computer oriented programming this is known as "indirect addressing" (in a certain location in the memory one finds the address of another value). In some other programming languages (in particular in assembly languages) a **ref** **ref** may be known as a "pointer" (i.e. by D6, xx and yy yield "pointers" to real variables, addresses of addresses of real values).

### 0.8.5. Identity relators, the cast, coercion

Where names are values in this language and may be manipulated as all other values (see 0.8.4), you may want to ask whether two names of the same mode are the same name. Neither the equals-symbol `==`, nor its negation `≠` can serve this purpose, because they are operators defined to compare values of certain modes only (and these values are mostly not names). To compare names, we have the identity-relators `:=:` (or `is`) and `≠:` (or `:/=` or `isnt`). For example, after the assignation:

$$y := x$$

it is most certainly **true** that

$$y = x$$

but it is also **true** that nevertheless:

(E34) $y \text{ isnt } x$ or $y \neq x$

because $y$ and $x$ yield different names (references to different locations on the stack).

(E35) $y \text{ is } xory$ or $y := xory$

however, is **true** or **false** depending on the value lastly yielded by *random* (see D5 in 0.8.2) and independently of whether $y = x$ or $y \neq x$.

Observe also that after the assignations:

$$xx := y; yy := xx$$

or, in one phrase:

$$yy := xx := y$$

nevertheless:

$$yy \neq x \text{ or } yy \text{ isnt } xx$$
because yy and xx yield different names (the mode of which is **ref real**);
reconsider E34 and its motivation.

One might now be disappointed that after the assignation yy := xx := y,
nevertheless yy isn't xx. In the nature of things it must be possible to get an
answer to whether names assigned to different pointers are the same. But
then the right question must be asked, and this question lies one level of
reference below the question yy := xx.

We could go down one level in reference by declaring, for instance, the
**proc**/**ref real**/**ref real**

proc the name assigned to = (ref ref real aa) ref real: aa;

and then we get undoubtedly the proper answer when we call this procedure
to the left and to the right of the identity-relator:

the name assigned to (xx) :=: the name assigned to (yy)

The **ref real**: in front of the reference-to-reference-to-real-unit aa "coerces"
this unit to yield its reference-to-real value. Fortunately, it is not necessary to
declare such a monstrosity of a procedure. You may write:

(E36) **ref real** (xx) :=: **ref real** (yy)

The technical term for **ref real** (xx) is ‘cast’. A cast, in general, coerces its
body to yield a value of the mode it dictates (if possible).

The cast may also be used to assign a value to the name assigned to a
pointer:

(E37) **ref real** (xx) := y

comes, in the context of E33*, to the same as:

x := y

You might ask now why we did not meet the cast at a much earlier stage;
why, for example, we did not have to write:

a := real (b), which, by the way, is correct ALGOL 68

The answer is that in all current situations where it is clear from the context
what you want, your computer will be so kind as to coerce your units to your
will. As a matter of fact, "coercion" is the technical term for the provision
that:

when no ambiguities make trouble,
your units will be implicitly coerced to the mode you
apparently require.
The time has not yet come to discuss all the slings and arrows of coercion.
Here we set a pointer to 1.1.6 and another one to 5.1.0.

## 0.9. Structures and other new modes

Besides the multiple, you will find in this language another system that gives you control of a collection of values, and that is in the form of a structured value (or "structure" for short). The individual values in a multiple are its "elements", the individual values in a structure are its "fields". The elements in a multiple are all of the same mode, `[1:n] real`, `[1:80] char`, `[1:5] proc void` etc.; the fields of a structure on the contrary may be of different modes, although there are very useful (even standard) applications where the field modes are the same.

### 0.9.1. complex values, vectors etc.

By declaring:

(D7) `mode compl = struct / real re, real im);`
`c another built in mode like string c`

or

`mode compl = struct / real re, im);`
`c an obvious contraction c`

a new mode `compl` (complex) is defined consisting of two real values; one of them is selected by the field-selector `re`, the other by `im`. Although field-selectors look the same as identifiers, you must not confuse them.

Now the variable-declarations:

(D8) `compl w, z;`

ascribe to `w` and `z` the names `w̄` and `z̄` which refer to structures as defined in D7 (i.e. `w` and `z` are `compl` variables).

The fields of `w` and `z` (the real and imaginary part of these complex variables) may be selected as follows:

(E38) `x := re of z; y := im of z;`

The `re` of and `im` of select the field in much the same way as, for instance, `[i]`, `[i,j]` etc. select the element in a multiple. There is, however, an important distinction: the selection of a field may be done at compile time, whilst the selection of an element in a multiple usually involves computation and, consequently, can then only be done at run time.
After the declarations D8, the identifiers *w* and *z* yield **ref compls**; the situation may be depicted as follows:

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

The result of the assignation:

$$z := w$$

should be obvious. You may, however, also assign:

$$(E39) \quad z := (x, y)$$

which amounts to:

$$\textit{re of } z := x, \textit{ im of } z := y$$

The (*x*, *y*) in this context is a structure-display, the counterpart of a row-display.

The mode **compl** is built into the standard declarations of the language, and operators =, ≠, +, -, x, /, ↑, and a monadic operator **conj** are declared for it with the meanings to be expected. Moreover, we have (monadic) operators **re**, **im**, **abs** and **arg** which return a **real** when applied to a **compl**, and an operator ⊥ (or i or +x), which may be pronounced as plus-i-times, which makes a **compl** of two **real** operands:

$$z := x \perp y \quad \text{or} \quad z := x + x y$$
amounts to:

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

(see also 0.10.4).

As from **int** to **real**, there is automatic widening from **real** to **compl** (and via **real**, from **int** to **compl**). The assignation:

$$z := x := i := 1$$

results in $i = 1, x = 1.0, z = (1.0, 0.0)$

Other examples of new modes defined by structures with fields of the same mode might be:

(D9)
mode vec = struct ( real xcoord, ycoord, zcoord );
mode rational = struct ( int numerator, denominator );
vec v1, v2, v3;
rational r1, r2, r3;

These modes, however, are not built into the standard declarations. If you want to use them for new kinds of operands, then you have to declare operators for them; this can easily be done (see 0.10.7, 8.4.1 and 8.4.2).

### 0.9.2. Structures with mixed mode fields, chains etc.

The really interesting feature of structured modes is, however, that you can collect values of different modes into them. For example:

(E40)
mode book = struct ( string text, int index );
book revised report on the algorithmic language algol 68;

Now the field:

text of revised report on the algorithmic language algol 68

contains the **string**: "may be difficult for the uninitiated reader" [see R 0.1.1], and:

index of revised report on the algorithmic language algol 68

might be the point where you really got stuck.

There is, however, another

book informal introduction to algol 68 revised edition

which also contains the **string** denoted, but in quite another context. May this other **book** help you to proceed at the **index of** referred to above.
An important implication of the concept of mixed mode fields is that you
can make a field refer to another structure of that same mode. In this way
chains (lists, queues, etc.) can be defined in a most natural manner. For
example:

(E41) **mode volume** = **struct** ( string *text*, int *index*,
                          ref *volume* *companion*, next );
    *volume* *report*, *informal introduction*,
    *revised report*, *informal introduction revised*;

The assignations:

(E42) *companion of report* := *informal introduction*;
*companion of revised report* := *informal introduction revised*;

have been made. Moreover we can report that:

(E43) *next of report* := *revised report*;
*next of informal introduction* := *informal introduction revised*;

There will be no *next of revised report*, neither a *companion of informal introduction* nor of *informal introduction revised* nor a *next of informal introduction revised*. To express this, we assign:

(E44)
*next of revised report* :=
*companion of informal introduction* :=
*companion of informal introduction revised* :=
*next of informal introduction revised* := *nil*;

where *nil* is the same as "a reference to no value at all".

We may speak about:

text of *companion of revised report*

which is the text under your very eyes at this moment.

It is important to comprehend the mode of the *companion* and *next* fields
of, for example, *revised report* and *informal introduction revised*. To these
identifiers **volume** variables have been ascribed and their mode is,
consequently, *ref volume*. Likewise, and this is the important point,
*companion of revised report* yields a *ref volume* variable, and so its mode is
*ref ref volume*; hence, *companion of revised report* is a "pointer" as are
*companion of report*, *next of report* and *next of informal introduction*.

From this it follows that in E42 and E43 names have been assigned to
pointers rather than (non *ref*) values — you will not find the *text of informal
introduction revised* in the *revised report*, but via the pointer *companion of*
revised report you find a reference to that text. A more complete discussion of this rather delicate matter will be found in Sections 1.4.3 and 5.4.2.

To conclude, we consider an example in which names will be assigned to
**ref** fields.

(E45)
**mode card** = struct ( int value , string colour , picture ,
                 ref card next ) ;
**mode deck**= struct ( int number , ref card one ) ;
[0:51] card card ;
deck myhand , yourhand ;

In E45 we declared 52 cards and two decks, each of which may refer to a
certain card by its field one of myhand (one of yourhand). Which cards you
and I then have in our hands may now follow from the fields next of card [i] ;
number of yourhand may be the number of cards you have in your hand.

Leaving the value, colour and picture of the cards for what they are, we
may assign:

(E46)
**for i from 0 to 51 do next of card[i]** := card [(i + 1) mod 52] od ;
**yourhand** := ( 52, card[0] ) ; **myhand** := ( 0, nil )

where **mod** is the standard operator yielding the value of the left-operand
modulo the right-operand. We thus arranged our 52 cards in a circular chain
and you have them all in your hand.

You may now remove a **card**, say *card* [37], by:

next of card [36] := card [38]

and give it to me:

one of myhand := card [37] ;

next of card [37] := card [37]

¢ we made card [37]

selfreferring ¢

which you could have done in one statement:

one of myhand := next of card [37] := card [37]

You may give me another **card**:

next of card [28] := card [30] ;

next of card [37] := card [29] ;

next of card [29] := card [37]

We may administer these two events by:

number of yourhand -:= 2 ;

number of myhand +:= 2
<figure><img src="image_18.png" /></figure>
## 0.10. Routines and operators

A routine may be ascribed to an operator (see 0.7). An operator is represented by a symbol, such as:

```
+ - x / ÷ ↑ ↓ ∨ ∧ ∨↓ < <= = ≠ ≥ >
< = > = + x / x
+ := - := x := / := etc.
```

or by a bold word (representing a symbol), such as:

over up down or and not i lt le eq ne ge gt
plusab minusab timesab divab upb lwb re im etc.

You can make as many operators as you need:

plus minus times div pow
nor impl parl perp abc m n o p etc.

We have to distinguish between two kinds of operators:

1) monadic: the routine has one formal-parameter;
   a monadic-operator is always applied to the operand to its
   right (prefix notation),

2) dyadic: the routine has two formal-parameters;
   a dyadic-operator is always applied to the operand to its
   left (the left-operand) and to its right (the right-operand),
   (infix notation).

The monadic operators always have a higher priority than all the dyadic ones; for the latter nine priority levels are provided. The priority of a newly defined operator is declared by a priority-declaration:

prio o = 3;

An operator will normally be used to return a value. The natural use of
operators is in formulae. Routines yielded by operators are therefore always
routines with either one or two formal-parameters, usually returning a value.
Operation-declarations look like procedure-declarations; the only difference
lies in the use of op instead of proc.

In this section we shall confine ourselves to taking over some of the
operation-declarations from the standard-prelude [R 10.2]. They may speak
for themselves and reading them is one of the ways of learning the language.
At this point (or at a point a little further on in this section), you might
decide to try some close reading in R 10.2.3. Anyhow, the examples we give
here illustrate how to declare and use your own operators.

0.10.1. Operations on boolean operands

R 10.2.3.2

<table>
  <tbody>
    <tr>
      <td>op abs</td>
      <td>=(bool a) int:</td>
      <td>if a then 1 else 0 fi;</td>
    </tr>
    <tr>
      <td>op &#8700;</td>
      <td>=(bool a) bool:</td>
      <td>if a then false else true fi;</td>
    </tr>
    <tr>
      <td>op &#8702;</td>
      <td>=(bool a, b) bool:</td>
      <td>if a then true else b fi;</td>
    </tr>
    <tr>
      <td>op &#8703;</td>
      <td>=(bool a, b) bool:</td>
      <td>if a then b else false fi;</td>
    </tr>
    <tr>
      <td>op =</td>
      <td>=(bool a, b) bool:</td>
      <td>(a &#8702; b) &#8719; (&#8700; a &#8702; &#8700; b);</td>
    </tr>
    <tr>
      <td>op &ne;</td>
      <td>=(bool a, b) bool:</td>
      <td>&#8700; (a = b);</td>
    </tr>
  </tbody>
</table>

These declarations express neither more nor less than the fundamental
truth tables of elementary boolean algebra. You might subjoin in your own
library (it is not in the standard-prelude):

$$
\begin{align*}
\mathbf{prio\ impl} &= 5; \\
\mathbf{op\ impl} &= (\mathbf{bool}\ a, \ b)\ \mathbf{bool}: \neg(\mathbf{a} \ \mathbf{and} \ \neg\mathbf{b});
\end{align*}
$$

Pay some attention to the definition of equality of two boolean operands:
the first occurrence of the symbol = is the operator to be defined; the second
occurrence is the is-defined-as-symbol which is part of all identity- and
operation-declarations.

0.10.2. Formulae

Routines ascribed to operators are activated by the formulae in which
those operators occur. Compare, for instance:

$$
\begin{array}{l@{\qquad}l}
(\text{E47}) & \mathbf{op} \lor = (\mathbf{bool} \ a, \ b) \mathbf{bool}: \mathbf{if} \ a \ \mathbf{then} \ \mathbf{true} \ \mathbf{else} \ b \ \mathbf{fi}; \\
& \mathbf{proc} \ or = (\mathbf{bool} \ a, \ b) \mathbf{bool}: \mathbf{if} \ a \ \mathbf{then} \ \mathbf{true} \ \mathbf{else} \ b \ \mathbf{fi};
\end{array}
$$

Both $\lor$ and $or$ yield (different instances of) the same routine. Therefore, the
formula $p \lor q$ returns the same value as the call $or(p,q)$.

There is, however, a very important distinction between the elaboration of
a formula and that of a call. In a procedure-call it is the procedure-identifier
 irr espective of the actual-parameters) which appoints the routine to be
activated. In a formula, the mode of the operands, as well as the operator
itself, is taken into account. In a procedure-call your computer will be so
kind as to coerce (if possible) your actual-parameters until they match the
modes required by the formal-parameters (ints may be widened into reals and reals into compls etc.). In formulae this kindness is restricted. There may be many different occurrences of the same operator token, yielding different routines depending on the (then necessarily different) modes of the formal-parameters. Therefore, the modes of the actual operands have a firm vote in the election of one of the routines nominated under the same operator.

Moreover, the same symbol may occur as a monadic- as well as a dyadic-operator, even in the same formula. It is always immediately clear from the context which of these two possibilities applies.

Let there be declared:

(E48.0) proc eq = (compl a, b) bool: abs a = abs b;

(E48.1) op = (compl a, b) bool: (re of a = re of b) ∧ (im of a = im of b);

(E48.2) op = (real a, b) bool: a ≤ b ∧ a ≥ b;

(E48.3) op = (int a, b) bool: a ≤ b ∧ a ≥ b;

(E48.4) op = (bool a, b) bool: (a ∧ b) ∨ (¬a ∧ ¬b);

(E48.5) op = (bool a) bool: (a | false | true);

prio ⊢ = 3;

(E48.6) op = (bool a, b) bool: a ∧ ¬b;

Now:

w = z invokes E48.1

x = y invokes E48.2

i = j invokes E48.3

p = q invokes E48.4

but:

eq(w,z)
eq(x,y)
eq(i,j)

all three call E48.0

because w and z are ref compls
x and y will be widened
i and j will be widened

} to

compl

however:

eq(p,q) is undefined, because a bool cannot be coerced to compl

but:

eq(abs p, abs q) calls E48.0, because abs p and abs q yield
ints which will be widened to compl
and in:

```text
    ⊢p ⊢⊢q
or
    ⊢(p) ⊢(⊢q)
```

the first occurring ⊢ is monadic, and invokes E48.5

the second occurring ⊢ is dyadic, and invokes E48.6

the third occurring ⊢ is monadic, and invokes E48.5

Apart from owning a routine, operators also have a certain priority which determines the parsing of the formula in which they occur. By inserting brackets in a formula, a different parsing can be obtained from that required by the "natural" priorities; in fact, priorities serve to avoid brackets.

Take, for instance, the formula `( c ∧ b ) ∨ ( ⊢a ∧ ⊢b )`. The operators ∧ and ∨ have different priorities (`prio ∧ = 3`, `v = 2`); consequently, the brackets are superfluous: `a ∧ b ∨ ⊢a ∧ ⊢b` yields the same value, though in a less transparent manner.

The monadic ⊢ is of higher priority than any dyadic-operator and therefore the brackets in, for instance `(a ∧ ⊢b)` are essential.

### 0.10.3. Operations on arithmetic operands, the standard prelude

Maybe a certain amazement will fall upon you in Section 10.2.3 of the Report. You will find there declarations such as:

[R 10.2.3.3.i] `op += (int a, b) int: a - b;`

[R 10.2.3.3.m] `op += (int a, b) int:`

    if `b ≠ 0`
    then `int q := 0, r := abs a;`
    while (`r -= abs b`) ≥ 0 `do q += 1` od;
    if (`a < 0` and `b ≥ 0`) or (`a ≥ 0` and `b < 0`)
    then `-q` else `q` `fi`
    `fi;`

and even worse, because you will also meet tokens not belonging to the language such as `L`, `P`, `Q`, `R`, `E` etc. which provide a kind of shorthand for the standard-prelude only.

These definitions of arithmetic operations (the meaning of which will be known to every programmer) have nothing to do with machine efficiency. To the contrary, their justification lies in the fact that they "fix the semantics" by defining all operations in terms of a certain minimal set of primitive operations. Agreement with the choice of this set and whether you like this method or not is a matter of taste (maybe even of philosophy); it has nothing to do, however, with the language defined. This is entirely a problem of how to define a language.

Moreover, a routine defines a series of actions in a computer and it is explicitly stated in the Report [R2.1.4.1.a] that any of these actions may be
replaced by any other action which causes the same effect. Consequently, an implementor is perfectly free to supply means for generating (more) efficient machine code, whenever he is able to do so. In particular, for the routines occurring in the standard-prelude (and also in the library-preludes, see 0.10.7), he can generate efficient machine code himself, taking advantage of every specific machine feature (most machines will have single commands for addition and integer division and, unless he is a maniac, your implementor will not follow the routines in the standard-prelude to the letter).

### 0.10.4. Operations on complex operands

mode compl = struct ( real re, im );

[R 10.2.3.7]

op $\perp$ = (real a, b) compl: (a, b);

op re = (compl a) real: re of a;

op im = (compl a) real: im of a;

op abs = (compl a) real: sqrt (re a $\uparrow$ 2 + im a $\uparrow$ 2);

op arg = (compl a) real:

if real re = re a, im = im a;

re $\neq$ 0 or im $\neq$ 0

then if abs re > abs im

then arctan (im/re) +

pi/2 x (im < 0 | sign re - 1 | 1 - Sign re)

else -arctan (re/im) + pi/2 x sign im

fi

fi;

op conj = (compl a) compl: re a $\perp$ -im a;

op = (compl a, b) bool: re a = re b $\land$ im a = im b;

op $\neq$ = (compl a, b) bool: $\neg$(a = b);

op + = (compl a) compl: a;

op - = (compl a) compl: -re a $\perp$ -im a;

op + = (compl a, b) compl: (re a + re b) $\perp$ (im a + im b);

op - = (compl a, b) compl: (re a - re b) $\perp$ (im a - im b);

op x = (compl a, b) compl: (re a $\times$ re b - im a $\times$ im b) $\perp$ (re a $\times$ im b + im a $\times$ re b);
$$ \begin{array}{l} \texttt{op / = (compl a, b) compl: ( real d = re (b x conj b);} \\ \texttt{compl n = a x conj b; } \\ \texttt{(re n/d) \perp (im n/d));} \end{array} $$

$$ \begin{array}{l} \texttt{op \uparrow = (compl a, int b) compl:} \\ \texttt{(compl p := 1;} \\ \texttt{to abs b do p := p x a od;} \\ \texttt{(b \ge 0 | p | 1/p)} \\ \texttt{);}} \end{array} $$

We could subjoin another operator to this set, which the authors seem to have forgotten: the monadic i (or $\perp$ which is, however, a less appropriate representation in this case):

$$ (D10) \quad \texttt{op i = (int a) compl: (0, a);} $$

$$ \texttt{op i = (real a) compl: (0, a);} $$

Instead of $x \perp y$ (or $x \text{ i } y$) you could then also write $x \text{ + } i \text{ y}$, which is closer still to the usual mathematical notation.

### 0.10.5. Operations combined with assignations

[R 10.2.3.11]

$$ \texttt{op +:= = (ref real a, real b) ref real: a := a + b; \$ or plusab \$} $$

$$ \texttt{op -:= = (ref real a, real b) ref real: a := a - b; \$ or minusab \$} $$

$$ \texttt{op x := = (ref real a, real b) ref real: a := a \times b; \$ or timesab \$} $$

$$ \texttt{op / := = (ref real a, real b) ref real: a := a / b; \$ or divab \$} $$

The first formal-parameter has to be ref, because we want to assign to it. The value returned has also been declared to be ref, and some consequences of this are shown in 6.3. These operators are declared for all arithmetic operands (int, real and compl).

### 0.10.6. Operations on strings

The standard mode string is defined as follows:

$$ \texttt{[R 10.2.2] mode string = flex [1:0] char;} $$

The flex in front of the `[1:0]` means that the bounds of a string may be reset by assignation (compare 5.5.4.1) — i.e. a string is a multiple which is allowed to “breathe” — initially a string is empty, which is expressed by `[1:0]`, the upper-bound being less than the lower-bound.

It is instructive to unravel the operations on strings. In doing so we meet
the at-symbol @ (or at) which arranges for the bounds of the actual strings to be considered (by "sliding" them) to have a lower-bound 1.

[R 10.2.3.10]

op <= ( string a, b ) bool:

begin int m = upb a[@1] ; n = upb b[@1] ; int c := 0 ;
    for i to if m < n then m else n fi
    while ( c := abs a[@1][i] - abs b[@1][i] ) = 0
    do skip od;
    if c = 0 then m < n and n > 0 else c < 0 fi

end;

op <= ( string a, b ) bool: ¬( b < a )
op = = ( string a, b ) bool: a <= b and b <= a
op ≠ = ( string a, b ) bool: ¬( a = b )
op >= = ( string a, b ) bool: b <= a
op > = ( string a, b ) bool: b < a

op + = ( string a, b ) string:

begin int m = if int la = upb a[@1]; la < 0 then 0 else la fi,
               n = if int lb = upb b[@1]; lb < 0 then 0 else lb fi;
[1:m+n] char c;
c[1:m] := a[@1]; c[m+1:m+n] := b[@1];
c

end;

op x = ( string a, int b ) string: ( string c ; to b do c := c + a od ; c ) ;

op x = ( int a, string b ) string: b × a

0.10.7. The library prelude

The operation-declarations considered thus far belong to the standard-
prelude of the language, i.e. they are built in. You will also find in the
standard-prelude all environment enquiries and all declarations for formatless
and formatted input and output (which therefore are also built into this
language).

Nothing, however, prevents you from subjoining to this standard-prelude a
set of home made declarations. Of course you are free to declare such new
things in your own particular-program; but, as soon as you want to apply
them in several programs, or you want to enable others to use them, or you
have reason to expect that more efficiency may be acquired, then you can go
to your implementor and ask him to make the whole set an as efficient as
possible extension of the standard-prelude, i.e. a 'library-prelude'. In that way an arbitrary number of problem oriented dialects may be defined. For some possible examples see 8.4 and 8.5.

The possibility of subjoining library-preludes to the standard-prelude contributes in no small measure to the flexibility of this language and this is one of the basic concepts of ALGOL 68.

You should, therefore, never accept an implementation in which library-preludes cannot be coded efficiently or in which the attachment of one or more library-prelude(s) to the standard-prelude cannot easily be done.

## 0.11. bits and bytes, longs and shorts

On most modern computers you will find, if not in the hardware then in the standard software, provision for the manipulation of single bits in a machine word, of parts of machine words (byte-addressing) and also for double and maybe even multilength arithmetic.

In a concrete computer, all instances of values of all modes will be stored as bit-patterns. Whether a specific bit-pattern may correspond to a value of a specific mode or not is mainly a matter of how the standard software may interpret that piece of binary information. That is to say the interpretation of bit-patterns and also the arrangement, size and structure of their locations in the memory is almost entirely a matter of software.

In this language, the possibility of considering (a part of) a machine word as a mere sequence of bits is reflected in the mode **bits** (0.11.1), the particular interpretation of a "byte" as a **char** (i.e. the interpretation of one or more machine words as representing a fixed sequence of **chars**) is reflected in the mode **bytes** (0.11.1) and the possibility of multilength arithmetic is reflected in the **long** - - - **long** modes (0.11.2). To what extent available hardware features will be used for these further modes and to what extent (and how) they will be simulated by software provisions is entirely a matter of implementation.

### 0.11.1. The modes bits and bytes

Both **bits** and **bytes** are defined to enable the programmer to take advantage of certain (hardware-) features of the machine on which the language is implemented. A **bits** will be something pretty close to a machine word and the environment enquiry *bits width* is then the wordlength. A **bytes** may be a memory unit in which a certain number of characters can efficiently be stored; a **bytes** may be considered as a string of fixed length *bytes width*.
Operators are defined for **bits** and **bytes** reflecting the most current machine operations.

For **bits** we have `=` and `≠` to compare them, and `∩` (disjunction), `∧` (conjunction), `shr` (shift left), `shr` (shift right), `abs` (from **bits** to **int**), `bin` (from **int** to **bits**), an operator **elem** (selects a certain bit from a **bits**) and some others.

For **bytes** we have the comparison operators as for **strings**, **elem** as for **bits** and a transfer from **string** to **bytes**.

(D11) **bits** *t*; **bytes** *r*;

declares *t* to be a **bits** variable, and *r* to be a **bytes** variable.

For **bits** we have a separate denotation, consisting of a sequence of digits 1 (the equivalent of **true**) and 0 (the equivalent of **false**), preceded by 2*r* to indicate that the sequence following is to be understood as a number in binary representation (radix 2). If we assign:

(E49) $t := 2r1011100100001$

and bits width is, say, 32 then $\hat{t}$ refers to a machineword (a **bits**):

`2r 00000000000000000001011100100001`

The value of **abs** *t* is now 5921 (conversely, the value of *t* is **bin** 5921).

If we now assign:

$t := t \land 2r111111$

then the value of *t* becomes 2*r* 100001. Then, after the assignment:

$t := t \mathrm{shr} 3$

the value of *t* is 2*r* 100001000, so that 29 **elem** *t*, i.e. (bitswidth-3) **elem** *t*, is **true**, but 30 **elem** *t* is **false**.

If we want to consider the **bytes** *r* as a **string**, then we may apply a cast, e.g.

`s plusab string (r)`

Just to demonstrate **bits** and **bytes**, we consider the following example:
(E50)

proc compose string =
  ( bits select , ref [1: bits width] bytes phrase ) string:
  ( string s ; ¢ initialization is not necessary, because
     the flexible bounds are set to 0 and 1 at
     the declaration (see D3 in 0.4.3) ¢
     for i to bitswidh
     do if i elem select then s plusab string ( phrase[i] ) fi od;
     s );

0.11.2. The long and short modes

The prefices **long** and **short** play a role in the creation of new modes in
much the same way as [ ] , **struct** , **proc** and **ref** do; the **long** or **short**,
however, may stand only in front of **int** , **real** , **compl** , **bits** and **bytes** and of
all long and short modes derived from these.

In the standard-prelude you will find environment enquiries such as:

int int lengths = c the number of different lengths of integers c;

int int shorths = c the number of different shorths of integers c;

stating to what extent the long and short feature is implemented for ints, and
correspondingly for reals, bits and bytes.

Now, if we declare, for instance:

long long long long long long long int i i i i i i i i i i ;

but int lengths = 3, then the value of our i i i i i i i i i i will be treated as if it had
been declared:

long long int i i i i i i i i i i i ;

Hence, *int lengths* = *3* means that your implementor will distinguish only
three kinds of integral values: *int*, *long int* and *long long int*. The same
applies to *real* (and, consequently, to *compl*), *bits* and *bytes*. The number of
*longs* characterizes the degree of discrimination with which the value is kept
in the computer.

In the language the prefices long and short also turn up in denotations:

iiiiiiint := long long long long long long long 0

In the standard-prelude you will also find the environment enquiries:

long int long max int = c the largest long integral value c;

short int short max int = c the largest short integral value c;

long long int long long max int = c the largest long long integral value c;

etc.
short real short max real = c the largest short real value c;

short real short small real = c the smallest short real value which can be
usefully compared with short 1.0 c;

long real long max real = c the largest long real value c;

long real long small real = c the smallest long real value which can be
usefully compared with long 1.0 c;

etc.

For the arithmetic modes (**int**, **real**, **compl** and their **longs** and **shorts**) we have a monadic-operator **leng** which makes the operand one **longer**, and a monadic-operator **shorten** which takes away one **long** or adds one **short**.

There is no automatic transfer between different **longs** and **shorts** of the same basic mode.

For example:

(E51) proc inprod = ( ref [ ] real a, b ) real:
( long real value := long 0.0 ;
for i
  from ( lwb a < lwb b | lwb b | lwb a )
  to ( upb a > upb b | upb b | upb a )
  do value += leng a[i] x leng b[i] od;
shorten value );

If, in a call of E51, the bounds of the actual rows are not equal, then the
routine will compute the innerproduct as if the rows had been supplemented
with zero elements until their bounds matched.

0.12. Unions

United modes (**unions** for short) are brought into existence to enable the
programmer to specify locations in which values of different modes can be
stored, and to dispose of the names which refer to such accommodating
locations. In particular, with the aid of **unions** you can define routines which
accept actual-parameters and (or) return a value of one of several possible
modes.

The mode-declaration:

(E52) mode strint = union ( string , int );

declares **strint** to be a new mode encompassing both the mode **string** and the mode **int**. It is important to know that this does not define a new kind of value; a new mode has been declared. The values in this mode, however, are still **strings** or **ints** (see also Section 1.6.1).
The variable-declaration:

(E53) loc strint year;

ascribes to *year* the name of either a *string* or an *int*. Thus *year* is a *ref strint* identifier.

A *ref strint* is, most certainly, a new kind of value (i.e. it is neither a *ref string*, nor a *ref int*), it is a *ref union* (*string*, *int*), but it does not refer to a "*strint*" because there is no such thing.

You may now assign to *year*:

(E54) year := "1968"

as on another occasion:

(E54*) year := 1968

Observe, that in the context of:

(E55) string text, int numb;

neither the assignation *text* := 1968, nor the assignation *numb* := "1968", is allowed.

The assignations E54 and E54* may be depicted as follows:

<figure><img src="image_19.png" /></figure>
<figure><img src="image_20.png" /></figure>

Once you have declared a united variable, you may want to ask the mode of the value assigned to it. It may be clear that this requires mode checking at run time. However, this is in fact the only situation where, in this language, run time mode checking is inevitable and for no other reason than that the programmer has explicitly asked for it.

In the context of E52 --- E55 you may write:

(E56)

```
case year
    in ( string ) : true ,
    ( int ) : false
esac
```

This unit is a 'conformity-clause'. It yields upon elaboration the value **true** if *year* refers to a **string** (which is the case, for instance, after the assignation E54): otherwise its value is **false** (which is the case after E54*).

The expressions `text := year` and `numb := year` are not correct assignations in this language, not even when the modes conform. Therefore we have a slightly more extended form of the conformity-clause:

(E57)

```
case year
    in ( string s ) : text := s ,
    ( int i ) : numb := i
esac
```

If we want to know which of the two assignations has been elaborated we might declare:
(E58) **proc deliver** = ( ref string t , ref int n , strint tn ) bool:
    case tn
        in ( string s ): ( t := s ; true ),
        ( int i ): ( n := i ; false )
    esac;
    deliver ( text , numb , year )

The call *deliver* (*text*, *numb*, *year*) delivers the actual value of *year* to the right destination. The value of *deliver* is **true** or **false** depending upon the mood of the year.

An example of a procedure yielding a value of one of two possible modes
may be (in the context of the declarations E23* and E23**, see 0.7.3):

(E59*) **mode intreal** = **union** ( **int** , **real** );

(E59) proc factorial = ( int n ) intreal:
    if n > nmaxfac
    then faclarge (n)
    else int f := 1;
        for i from 2 to n do f x := i od ; f
        of which case an int value is yielded ♦
    fi;

The difference with E23 is that any call of the there declared
proc( int /real fac) yields a real (the int computed in the else-part is widened
to real because such is required), so that you can not know whether the value
returned was an exact factorial or not. A call of the proc( int /intreal
factorial, on the contrary, yields an int or a real and you can find out which
of the two was the case.

Beware, however, of a pitfall.

You cannot assign:

y := factorial (m)

nor:

i := factorial (m)

because an "**intreal**" can neither be assigned to a **ref real** nor to a **ref int**.

The way to achieve this, of course, is:

case factorial (m)
in (real r): y := r,
(int n): i := n
esac
As a final example consider:

(E60) mode numb = union ( int , real , compl );

proc gamma = ( numb u ) numb:

case u

in ( int i ):

if i > 0

then case i

in 1, 1, 2, 6, 24, 120, 720, 5040,
40320, 362880, 3628800, 39916800,
479001600

out faclarge (i-1)

esac

fi,

( real r ) : c algorithm for the gamma function with
a real argument r , yielding a real value c ,

( compl c ) : c algorithm for the gamma function with
a compl argument c , yielding a compl value c

esac

0.13. Local and global generators, stack and heap

We know that by a variable-declaration like

loc real x ;

a real value is generated on the stack. To put it more precisely:

The "local-generator" loc real generates on the stack a new real value
(its "side-effect" so to speak) and it yields upon elaboration the ref real
name ȳ which is then ascribed to the identifier x.

A less concise way to formulate this happening is:

ref real x = loc real ;

in which we meet the local-generator as a unit.

An interesting example of the use of a local-generator outside a variable-declaration or an identity-declaration is given by the following phrases in which a triangular matrix is generated:

(E61) loc [1: n] ref [ ] real triang ;

for i to n

do triang [i] := loc [1: i] real od ;
Observe that *triang* is declared to yield a singly subscripted row of names:
*triang[i]* yields the name of a [] *real*; *triang[i,j]* is undefined. If you want to access the [i,j]th element of *triang*, you must write:

`triang[i][j]`

You then access the *j*th element of the row referred to by the *i*th element of *triang* (for further discussion, see 5.7.2.E10).

The generator **loc real** is a local-generator because the **real** value it generates ceases to exist as soon as the range to which the value was **local** is completed (i.e. as soon as we leave that range). Not only the relation between the identifier **x** and the **ref real** ascribed to it ceases to hold, but also the **real** value it referred to vanishes as the stack contracts. We must know that a serial-clause is a local range when it contains at least one declaration — therefore the clause between **do** and **od** in E61 was not a local range and we could take the **ref [] real** value with us outside the **do** and **od**.

Now, what can we do when we want to take a value and its name outside a local range, for example when the serial-clause between **do** and **od** contains a declaration? Or, to put it differently, how can a location (a box) survive a contracting stack?

The solution in this language is the presupposition of the “heap”: another storage allocation regime besides the stack, in which values may be generated which remain there as long as some name refers to them.

By a variable-declaration like:

`heap real hx;`

or an identity-declaration:

`ref real hx = heap real;`

a **real** value is again generated, and the global, or "heap", generator **heap real** yields its name.

For example:

(E62)

`loc [1: n] ref [] real zigzag;`
`for i to n`
`do loc int length; read (length);`
`zigzag [i] := heap [1: length] real`
`od;`

Here the local-generator loc[1: length] real would not work, because the stack will contract at the completion of the serial-clause between do and od which now is a local range because it contains the declaration loc int length;.
For an example of a heap variable-declaration consider:

(E63) **mode record** = struct (string *name*, int *date of birth*, real *value*, ref record *next*),
**mode society** = struct (ref record *first*, *last*);
**loc society** *high*;

Now assume a large file of records defining potential members for the *high* society. We want a procedure *try* to scan that file and try every record for acceptability on the ground of age and minimal value required. The procedure *try* has to yield *false* when the record under consideration is not acceptable; if it is (the rare cases) it must generate a seat in the society and yield true. A procedure always defines a local range, so we must apply a heap-generator:

**proc try** = (int *date*, real *minimum*) bool:
    **if heap record new;**
        **read** ((*name* of *new*, *date of birth* of *new*,
                   *value* of *new*) );
        **next of new** := nil;
        **date of birth of new** < *date* and *value of new* > *minimum*
    **then last of high** := *next of last of high* := *new*;
        **¢ in which case new survives ¢**
        **true**
        **else false** ¢ in which case new is thrown away ¢
    **fi**;

Now let us generate the founder member:

*first of high* := *last of high* :=
*heap record* := ("Methuselah", 0, 1000.0, nil);

and examine the first hundred candidates, who are apparently required to be
no more than 50 years younger than *Methuselah*, and to be not much lower
in value than their predecessors.

**to 100**
**do** if *try* ((*date of birth of first of high* ) + 50,
.95 × (*value of last of high*) )
then *print* ( (name of last of high, newline) )
**fi**
**od**

0.14. What to do next

The remainder of this Introduction contains, in a two-dimensional way,
eight (or seven) chapters (please now refer to the table of contents). The eight
horizontal chapters are:

1. BASIC CONCEPTS

2. DECLARATIONS

3. CLAUSES

4. ROUTINES

5. UNITS

6. STANDARD PRELUDE

7. TRANSPUT

8. EXAMPLES

The seven vertical chapters are:

.1 FUNDAMENTALS

.2 PROCEDURES AND NAMES

.3 OPERATIONS

.4 STRUCTURES

.5 MULTIPLE VALUES

.6 UNIONS

.7 DISTINCTIVE FEATURES

Thus the horizontal chapters are subdivided into seven sections “.1” through “.7”. Likewise, the vertical chapters are subdivided into eight sections “1.” through “8.”

You may read row-wise:

for *i* to 8

do for *j* to 7 do *elaborate section [i,j] od od*

or you may read column-wise:

for *i* to 7

do for *j* to 8 do *elaborate section [j,i] od od*

The latter (vertical) route is the more didactic one, for those who wish to learn the language. The horizontal one (along which this Introduction has been bound) is more appropriate for those who wish to survey the essential principles of the language as a whole. In particular, the first chapter on BASIC CONCEPTS is a survey of the main part of the basis on which the language was “orthogonally designed” [R 0.1.2]; i.e. the generalized concept of “mode”, and all its consequences.

If you are now in some doubt as to which route is for you, then take our suggestion — read horizontally in Chapter 1 until you find the waters beginning to get a little deep: then return to 2.1 and read by the vertical route thereafter.
# 1. BASIC CONCEPTS

## 1.1. Fundamentals

You write or read a 'particular-program' which is embedded in an environment consisting of the 'standard-prelude' (and '-postlude') and a 'library-prelude'.

The standard-prelude is a comprehensive selection of features, generally accepted as a standard environment for a modern programming language. A library-prelude is a continuation of the standard-prelude. It may contain more specific features you would like to have at your disposal in certain classes of problem. The implementation is supposed to cater for some provision which enables you to subjoin one or, ideally, a selection of library-preludes.

The whole constitutes a 'program'.

### 1.1.1. Objects

A program may be parsed into a tree of "constructs", such as identifiers, denotations, formulas, procedures, declarations, clauses, etc. These are all classified as "external objects", since they comprise the written, external form of the program. A construct (or for that matter the whole program) may be "elaborated" by a "computer" (be it a human being or an automaton), whereupon a defined sequence of "actions" takes place and, upon the completion of these, a "value" is "yielded". With some constructs, the sequence of actions is the prime reason for the elaboration. With others, it is the value yielded which is important—indeed, in the case of identifiers and other such "indicators" there are no actions at all, and the value yielded is simply that which had previously been "ascribed" to that indicator in a declaration.

A "value" (or, more precisely, an "instance" of that value) must presumably be kept somewhere, either in the human's mind or in the memory of his automaton. A value is therefore classified as an "internal object". Each internal object (in the sequel often "object" for short) has three relevant attributes:

1) it is of some "mode",

2) it is a particular instance of a value of that mode,

3) it has some location.

1) The mode specifies how the object is built up from basic material (bits, or
the little grey cells in your brain) and to what kind of entities (numbers, characters, records, names, etc.) it is related. Partly this is a matter of implementation (the building of a real number for example), partly this construction may be specified by the program in terms of modes already defined (for example the building of a complex number as an ordered pair of real numbers). In the program text a mode may be indicated by a bold faced word, which is then to be considered as one indivisible symbol (e.g. **amode**). Such a mode-indication may be regarded as the badge of some class of values.

2) Some modes define but a few values (e.g. a **bool** can only be **true** or **false**), some quite a lot (e.g. **int** and **real**), some in principle an infinity (e.g. **string**); but there may be any number of instances of any particular value within the automaton, and such an "instance of a value" of some mode is an internal object.

3) An object is to be found somewhere, and this somewhere is its location (its address in the memory). The physical address is none of your business, but in many cases you will certainly want to have control of that location (for example you may wish to supersede the object by another instance of a value, or to enter its location in some chain), that is you may wish to "refer to" that object. As far as the location is concerned, there are two possibilities:

3a) The internal object was, in some previous declaration, "ascribed" to an external object (specifically, an indicator). Now you can always obtain the internal object by elaborating that indicator and inspecting its yield, but you still have no control over its location (because it may well be concealed in the object code) and you have to take it as it arises in the elaboration of the program, in which it is a "constant".

3b) The internal object is "referred to" by a second internal object (specifically, a "name"). In that case, its location is at your disposal in the form of that name. This gives you the right to supersede it, and it is therefore not a constant but a "variable". A name is an object of another (!) related mode—a 'reference to' (ref) mode. A ref amode object (a name) refers to an amode object.

You may visualize the interrelation of the concepts mode, value and name (which are of fundamental importance in this language) by drawing boxes in a "paper computer".

Boxes of the same shape then represent internal objects of the same mode. Each box holds an instance of a value (not necessarily different from the instance in another box). Names may come into the picture by drawing boxes of another shape, holding those names.

The relation "to refer" between two internal objects is depicted by an arrow pointing from the name to the object referred to by that name:
<figure><img src="image_21.png" /></figure>

We shall presently show you how actions may be depicted in our paper computer. They will always achieve the effects defined by the hypothetical computer in the Report (but sometimes by a different method).

### 1.1.2.Identifiers

In order to discuss internal objects, we need 'identifiers'. An identifier is a sequence of letters and digits with a leading letter, like *marlyn* and unlike *Imarlyn*.

The meaning of an identifier is defined in an 'identifier-declaration', of which there are two sorts—the variable-declaration (1.1.2.1) and the identity-declaration (1.2.2). (Alternatively, a label-identifier is defined as such when it occurs as a label in the program text.)

#### 1.1.2.1.Variable declarations

By declaring:

(E1) `loc amode object1, object2, object3;`

three internal objects are generated in the memory, each of them being an **amode**. Three names (**ref amode** objects) referring to the **amode** objects generated are then ascribed to the three identifiers. Therefore they are known as **ref amode** identifiers and the generated **amode** objects are 'variables'. In a picture: three boxes come about, each of them holding the name (location) of another box of the mode **amode**.

Now, *object1*, *object2* and *object3* are external objects, being constituents of the program. By the variable-declaration E1 an internal object is ascribed to each of them. The relationship between an identifier and the object ascribed to it cannot be changed; and the object ascribed (in this case a name) cannot be changed.
<figure><img src="image_22.png" /></figure>

We preferably draw external objects at the top of the diagrams in our paper computer (to separate them from the boxes, which are internal) and, if the elaboration of one of the external objects yields one of the internal ones (at the instant of time under discussion), we depict this by a line joining the two. The diagram above shows that, since **ref amode** objects have been ascribed to the identifiers *object1*, *object2* and *object3*, the yields of these identifiers will henceforth be the three objects drawn immediately below them. These objects are constant (the top row of boxes in our diagrams will generally depict constants). The boxes in the bottom row, however, are variable (we can see that this is so, because we can see that there exist names referring to them).

Thus, *object1*, for example, yields a constant name (**mode ref amode**) which refers to a variable *amode*. In the sequel we shall abbreviate this by saying, simply, that *object1* refers to that variable.

This is nothing new. In many other programming languages the proper relation between an identifier and its variable value is exactly the same, although perhaps you were never aware of it.

### 1.1.2.2. Assignation, collateral elaboration

If *mar1lyn* and *mar2lyn* are likewise declared to be **ref amode** identifiers (consequently yielding **ref amode** objects), then by assigning:

(E2) $object1 := mar1lyn; object2 := mar2lyn$

the object referred to by *object1* (*object2*) is “superseded” by an instance of the value referred to by *m ar1lyn* (*mar2lyn*). Nothing happens to the names ascribed to the identifiers. The value referred to by the LHS (Left Hand Side) becomes a copy of the value referred to by the RHS (Right Hand Side). The copy-action “to assign” is depicted below by a bowed arrow originating from
the object to be copied and pointing into the location of the copy:

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

Again this is nothing new. In most other programming languages the process of "assignment to a variable" takes place in exactly the same way.

In an assignment the LHS (the 'destination') and the RHS (the 'source') are elaborated "collaterally", i.e. there is no prescribed order for the actions of getting the name (the **ref amode**) in the LHS and getting the value (the **amode**) in the RHS. Consequently, if these two actions should happen to have any side effect upon each other (in the case of more involved assignations this could occur), then the result of the assignations is "undefined" (i.e. not defined by the Report alone).

In E1 also we met a collateral elaboration. In fact E1 involves three variable-declarations, the declaration of *object1*, of *object2* and of *object3*; and these three declarations are elaborated collaterally.

### 1.1.3.Phrases, serial and collateral elaboration

The piece of program text:

(E3)
**amode** object1, object2, object3;
object1 := mar1lyn;
object2 := mar2lyn

is a simple case of a 'serial-clause'. The "constituents" separated by semicolons are 'phrases' which may be either 'declarations' or 'units'. The semicolons represent the 'go-on-symbol'. The action defined by the phrase following a go-on-symbol begins after the completion of the action defined by the phrase preceding it.

As we have already pointed out, the variable-declaration:
`loc amode object1, object2, object3`

is a collateral-declaration. In fact it is a "contraction" of the phrase:

`loc amode object1, loc amode object2, loc amode object3`

The commas represent the 'and-also-symbol' and achieve the collateral creation of the objects.

The symbol loc expresses the act of generation of the variable (1.2.2.3), but it is optional in this context and is frequently omitted.

Besides collateral-declarations we may have serial-declarations, for example:

`amode object1; amode object2; amode object3`

and the go-on-symbols achieve serial creation of the objects (one by one). Eventual side effects (which in the case of more involved declarations could occur) now act precisely as prescribed by the order of elaboration thus defined.

Enclosing a serial-clause between "(" and ")" or "begin" and "end", we obtain a 'closed-clause':

(E4) ( amode object1, object2, object3; object1 := mar1lyn; object2 := mar2lyn; XXXXX )

By "XXXXX" we denote here and in the sequel an arbitrary constituent valid in the context.

By enclosing a serial-clause, a 'range' is demarcated (see also 3.1.5). A range has much in common with what in some other programming languages is known as a block: in particular it defines the "scope" of the values (names) created by the declarations within it.

A unit always yields a value of some mode (which may, however, be void if no value is actually required). For example, the unit:

`object1 := mar1lyn`

yields the value yielded by its LHS (and not, as you might have expected, the value yielded by its RHS), that is the **ref amode** object yielded by *object1*. An assignation yields the name in its LHS.

Correspondingly, a serial-clause yields a value of some mode, namely the value yielded by the unit which completes its action.

The same applies to closed-clauses.

For example, if XXXXX in E4 yields by elaboration an **amode** object,
(and *marilyn* is declared to be a *ref amode* identifier) then:

$$
(E5) \quad \textit{marilyn} ::= \left( \begin{array}{l} \textit{amode} \ object1, object2, object3; \\ object1 := mar1lyn; object2 := mar2lyn; \\ XXXXX \end{array} \right)
$$

is a perfectly sound assignation. It assigns the value yielded by E4, which is
the value yielded by XXXXX, to *marilyn*.

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

1.1.4. Routines

An internal object of fundamental importance is the "routine", which is
the internal equivalent to the sequence of symbols which comprises a
'routine-text'. A routine may or may not have formal-parameters, and may or
may not return a value of some mode. A routine-text is rather close to what
in some other programming languages is known as "a procedure-heading with
procedure-body".

In this language a routine may be ascribed, not only to an identifier, but
also to an 'operator'.

A routine may be “called”:

a) in a 'formula' by means of a operator yielding the routine,

b) or else by means of an identifier yielding (or, which may also be the case,
referring to) the routine, i.e. by a 'call'.

By declaring:

$$
(E6) \quad \texttt{op } \diamond = ( \textit{amode} \ formal1, formal2 ) \textit{amode} : XXXXX;
$$

the symbol “◇” is declared to be an operator, and the routine yielded by the
routine-text on the RHS is ascribed to it. In this routine-text, XXXXX is
some unit defining the action, using the formal-parameters *formal1* and
formal2. The amode: preceding it expresses that the routine is to return an
amode value.

By virtue of this declaration, the unit:

(E7) object3 := object1 ◊ object2

results in:

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

The routine ascribed to ◊ is depicted by a circle.

In E7 again, the LHS and the RHS are elaborated collaterally. The RHS is
a formula in which both ‘ operands ’, object1 and object2 , are in their turn
elaborated collaterally (corresponding to the fact that the formal-parameters
in E6 are separated by a comma). Formulas are described more fully in 1.3
and 5.1.3.

By declaring:

(E8) proc function = (amode formal1, formal2, formal3) amode: XXXXX;

the identifier *function* is declared, and the routine yielded by the RHS is
ascribed to it. In this routine-text, XXXXX is some unit defining the action,
using the formal-parameters *formal1*, *formal2* and *formal3*.

By virtue of this declaration, the unit:

(E9) màrilyn := function ( object1, object2, object3 )
results in:

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

Again, the LHS and the RHS are elaborated collaterally, as are the three actual-parameters *object1*, *object2* and *object3* on the RHS, by virtue of the commas between the formal-parameters in the routine.

### 1.1.5. Defining and applied occurrences

Consider the assignation:

(E5*)

```
marilyn := ( amode object1, object2, object3 ;
           object1 := mar1lyn ;
           object2 := mar2lyn ;
           object3 := object1 ◊ object2 ;
           function ( object1, object2, object3 ) )
```

To *marilyn* is assigned the value of a closed-clause. The outmost "(" and ")" enclose a serial-clause consisting of a collateral-declaration, followed by three consecutive assignations, in the last of which the RHS is a formula, followed by the call of a procedure returning an **amode** value. This value returned by *function* is now the value yielded by the closed-clause and consequently the value assigned to *marilyn*.
It might be worth your while to try to visualize the elaboration of E5* in one picture, in the same way as we did for the separate constituent phrases. You will meet then several "occurrences" of the identifiers *object1*, *object2* and *object3*, the first of which are the "defining occurrences" in the declaration *amode object1, object2, object3*. All other occurrences of these identifiers are "applied occurrences". Here we have a relation between two external objects, the technical term for this relation is "to identify": the second occurrence of *object1* identifies its defining occurrence. You might depict this relation by an arrow pointing from the applied occurrence to its defining occurrence.

### 1.1.6. Coercion

Every external object has, independent from the particular syntactic position in which it stands, an "a priori" value of some a priori mode. In order to make it fit its particular context, the external object may be "coerced", that is "forced to yield a value of another mode": its "a posteriori" mode and a posteriori value.

For example, the a priori mode of *marllyn* in E2 is *ref amode* (by virtue of its declaration), and thus its a priori value is a name (of an *amode* object). Now, by the assignation process as described in 1.1.2.2 ("getting the value" on the RHS), the a posteriori mode of *marllyn* must here be *amode* (we want the *amode* value referred to, and not the name). In this particular context *marllyn* must be "dereferenced", which is one of the six basic coercions in this language.

Observe that *object1* in E2 (the LHS of this assignation) is not dereferenced, but in E7 (in the syntactic position of an *amode* operand) as in E9 (in the syntactic position of an *amode* actual-parameter) it is.

Another example of coercion is "widening", implicit change from mode *int* to mode *real*, mode *real* to mode *compl*, and some others. Once you know what the term is about, you will find quite a lot of coercions in other programming languages, although perhaps they are not always so well defined if at all [see R6].

In a language in which the basic concepts are extended as far as possible, one must inevitably be very clear and precise on the subject of the actions concealed in the language. It is dangerous to presume actions to be implicit without stating exactly why, where and how. Of course, one could have supplied a certain number of operators, expressing explicitly the desired transitions from a priori to a posteriori mode and value. But then you would have been coerced into writing *object1 := DEREFERENCE marllyn* and
*object3* := **DEREFERENCE** *object1* ◇ **DEREFERENCE** *object2* or some
such, and very soon you would encounter much more miserable constructions
(see 5.1.0.2).

In ALGOL 68 at least six rather offensive monadic operators of this kind
are incorporated in the syntax, being implied by the syntactic position of the
external object to which they otherwise ought to have been explicitly
applied. This, indeed, complicates in no small measure the syntax. However,
once you have mastered that part of it [the whole of R 6], you will
appreciate that the burden is taken away from your shoulders. Apart from
that, coercion has one great charm: it does exactly for you what you want,
but could easily have forgotten. You will feel happy that you can write $x := i$
instead of $x := \text{WIDENTOREAL DEREFERENCE } i$. For a systematic
discussion of all the coercions, see Chapter 5.

Vertical readers, please turn to 2.1.

## 1.2. Names and declarers

### 1.2.1. Ascription and assignation

We have already introduced variables to you. They are internal objects and
new values can be "assigned" to them at any time and as often as you like.
This is natural, for why should it be called a "variable" if you cannot vary it?

A constant is, of course, quite a different thing. Obviously it cannot be
varied: it is an external object which is given a value once and for all, and the
process of giving it its once only value is termed "ascription". This process
can be brought about in identity-declarations (1.2.2) and in procedure calls
(1.2.3.2.1). It also arises in variable-declarations (as we have seen in 1.1.2.1),
but for a different reason. Behind each **amode** variable there hides a constant
**ref amode** name (it has to be a constant name, for otherwise you might lose
the variable). It is this constant name which is ascribed to the **ref amode**
identifier in a variable-declaration.

Often, when creating a new object, you have the choice of declaring it as a
constant or as a variable. Which should you do? (You might say that it does
not matter, since it will work either way, but this is a dangerous belief.) Take
our advice. If you do not intend to vary it again (at least within the lifetime
of the relevant range-see 2.2.1), declare it as a constant and ascribe its only
value to it. Variables are dangerous objects, and assignation is a dangerous tool.
### 1.2.2.Identity declarations

An 'identity-declaration' (defining the meaning of an identifier within its range) consists of an equals-symbol "=" with a 'formal parameter' on its left and an 'actual-parameter' on its right:

formal-MODE-parameter = actual-MODE-parameter

(The "MODE" stands for an arbitrary mode. In the syntax you will find a number of production rules starting with MODE, generating an infinity of different constructs. MODE is a so-called "metanotion"; the capitals express that there are separate metaproduction rules for it. You may forget this remark; everything will become clear in the sequel.)

A formal-MODE-parameter consists of a formal-MODE-declarer followed by a MODE-identifier. The formal-MODE-declarer determines the mode of the internal object which will be ascribed to that identifier:

<table><thead><tr><th colspan="3">formal-parameter</th><th></th></tr><tr><th colspan="2">declarer:</th><th>identifier:</th><th>this identifier is a:</th></tr></thead><tbody><tr><td></td><td>amode</td><td>thing</td><td>amode-identifier</td></tr><tr><td>ref</td><td>amode</td><td>name</td><td>reference-to-amode-identifier</td></tr><tr><td>ref</td><td>amode</td><td>pointer</td><td>reference-to-reference-to-amode-identifier</td></tr></tbody></table>

etc.

The actual-MODE-parameter yields an internal object to be ascribed to the MODE-identifier of the formal-parameter. We shall consider several possibilities for the actual-parameter:

1) a unit yielding the required mode (1.2.2.1 and 2)

2) a local-generator (1.2.2.3)

3) an initialized local-generator (1.2.2.3).

### 1.2.2.1 Constants

(E1) amode thing = marllyn;

The actual-parameter *marllyn* is a simple case of a unit and it yields a ref *amode*; *thing*, however, is declared to be an amode-identifier (by the formal-declarer *amode*). Consequently, *marllyn* must be dereferenced to yield an *amode* value and what happens is:
<figure><img src="image_27.png" /></figure>

Now, by this declaration, a copy of the value currently referred to by *marllyn* is ascribed to *thing*. You can never assign to such a *thing*, because it is not a name. You may consider *thing* as a constant and indeed, whatever may happen to the *amode* value referred to by *marllyn*, *thing* always yields the instance of an *amode* value it got from *marllyn* at its declaration. “Constant” is to be understood as “constant until next elaboration of the declaration”; then it may get a different value from *marllyn*.

Instead of *marllyn* we may write any unit yielding, after the proper coercions, the required mode:

(E1*) `amode thing = XXXXX;`

which may be depicted as follows:

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

### 1.2.2.2. Equivalences

(E2) `ref amode name = marllyn;`

Although here again, as in E1, the actual-parameter is a strong unit, this is a story completely different from E1.

The formal-declarer in E2 is *ref amode*; and the formal-declarer determines
the mode of the object to be ascribed to the newly declared identifier, in this case a 'reference to amode' value is required from the actual-parameter.

The a priori mode of *marllyn* happens to be reference-to-amode. Consequently no dereferencing of the actual-parameter is needed. A copy of the name yielded by *marllyn* is ascribed to the identifier *name*.

What happens is:

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

The result of the elaboration of E2 is that we have got two different identifiers, *name* and *marllyn*, yielding different instances of the same name and consequently referring to the same internal **amode** object.

Assigning to *name* or to *marllyn* has the same result (supersedes the same **amode** value); different identifiers but the same variable value.

In some other programming languages this phenomenon is known as "equivalence". In this language "equivalence" is only a particular case of a general (and extremely fruitful) construction.

### 1.2.2.3. Local generators

We may want an identity-declaration to create the name of a new object (we want to define a new variable). Then we choose for the actual-parameter a 'generator'. A generator "generates" a new object; a local-generator creates a new object on the "stack"; an amode-local-generator creates a new **amode** object on the stack. On creating a new object, the generator yields its name.

The new object created by a local-generator ceases to exist when the range in which it occurs has been elaborated up to the hilt.

A MODE-local-generator consists of the local-symbol "loc", followed by an actual-MODE-declarer; the amode-local-generator is loc amode. loc amode generates an amode object on the stack and yields its name on that special occurrence. We shall depict the creation of the amode object by a special kind
of arrow:

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

Now consider the identity-declaration:

(E3) `ref amode aname = loc amode;`

What happens is essentially the same as in E2:

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

The name yielded by `loc amode` is ascribed to the identifier `aname`, which consequently refers to the newly created `amode` object on the stack.

When the local-generator has done its work, the picture we are left with looks like this:

<figure><img src="image_32.png" /></figure>
But we have seen many pictures like this before. They were brought about by variable-declarations such as:

(E3*) `amode aname;`

It seems that `E3*` means exactly the same thing as `E3`. Every variable-declaration has an identity-declaration hiding behind it. Moreover, the **amode** in `E3*` is really a disguise for the generator **loc amode** in `E3`. Indeed, as was explained in 1.1.3, you may write the **loc** in `E3*` if you prefer:

(E3**) `loc amode aname;`

which goes to show why the **amode** in `E3*` must be regarded as an actual-declarer (remember that the **ref amode** in `E3` was a formal one). We can show how the process of generation enters into our pictures of variable-declarations in the following way:

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

We often wish to assign an initial value to a newly generated variable. Now consider the assignation:

(E4) `loc amode := marllyn`

This is, of course, a perfectly correct assignation. What happens is:

<figure><img src="image_34.png" /></figure>
The local-generator yields the name of the newly created **amode** object, which is initialized to the value referred to by *marllyn*; *marllyn*, of course, is dereferenced (compare 1.1.E2). So far so good, but we cannot do much with it, because no external object in the whole program yields the name of our new **amode**.

However, an assignation yields the value yielded by its LHS (see 1.1.3) which is **ref amode**. We may now consider E4 as a special case of a reference-to-amode-unit (compare E2) and write:

(E4') **ref amode aname = loc amode := marllyn;**

And see what happens:

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

We should expect there to be a variable-declaration corresponding to this, and indeed there is:

(E4*) **loc amode aname := marllyn;**
Please, do not confuse this with
**amode thing = marllyn;**
(see E1)

in which the **loc** is, as before, optional.

### 1.2.2.4. Variables and names

Syntactically, a 'variable' is a reference-to-MODE; a name.

Semantically, the object which is in fact "variable" is the object referred to.

Informally, we may choose an intermediate position and regard the pair of objects, consisting of an instance of a value and the name referring to it, as a variable:
<figure><img src="image_36.png" /></figure>

Going up one stair of references, we can generate variable names:

(E5) **ref** *ref amode pointer* = *loc ref amode*;

or the corresponding variable-declaration:

(E5*) **ref** *amode pointer*; Observe that again one **ref** is embezzled; it is a **ref** *ref amode* value that is ascribed to *pointer*.

What happens is:

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

This is essentially the same as E3. The generator **loc ref amode** generates a name on the stack. Such a **ref amode** on the stack may, by assignation to *pointer*, become an instance of a name referring to an *amode* object on the stack. In this way, "indirect addressing" is another fruit of the general concept of an identifier-declaration.

### 1.2.2.5. Casts

Consider the assignation:
(E6) pointer := marllyn;

Here the value referred to by *pointer* (a *ref amode* object) is superseded by the value yielded by *marllyn* (its a priori value; of course there is no dereferencing in this syntactic position; the required mode is *ref amode*).

What happens is:

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

Now the value referred to by *pointer* refers to the value referred to by *marllyn* (describing indirect addressing in a natural language always leads to muddling sentences). Observe the resemblance with the situation in E2, we do the same thing at one reference level higher.

We could also have achieved this in the declaration of *pointer*, again by an initialized declaration.

(E6*) ref amode pointer := marllyn;

To make things workable on the higher reference-to-something levels, we often need dereferencing in syntactic positions where coercion cannot do it for us; for example in the LHS of an assignation. In a reference-to-reference-to-MODE, we have at least two name levels, and we have to make clear which name is meant (how far down we want to assign). In E6* (*pointer* := *marllyn*) the value assigned is the *ref amode*.

Now suppose we want to assign the *amode* value of *object1* ◊ *object2* to the variable referred to by *pointer* (which is, after E6, the variable *marllyn*). We cannot do it without further preface. *pointer* is one *ref* above the level at which we want to assign.

Now the “preface” is a remarkable little magic wand termed a ‘cast’, which provides in many situations where coercion fails.
If we now write:

(E7) **ref amode (pointer) := object1 ♦ object 2**

the LHS is a cast obtaining a **ref amode** value from *pointer* (dereferencing it once), which is (after E6) the variable yielded by *marllyn*.

What happens is:

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

### 1.2.3. The metanotion MODE

In this language a mode is something you can define (declare) yourself in terms of other, already defined, modes (see 1.3.3.1). In the Report [R 1.2.1] you will find a set of metaproduction rules for "MODE", defining an infinite number of possible modes. They are all derived from the primitive modes:

**bool**, **char**, **int**, **real**, **bits**, **bytes** (see also Section 2.1.1)

There is also a special mode **void** (implying no value at all) which can turn up as the yield of a procedure (4.2.1) and also as the resident value of a **union** (5.6.1).

(Occasionally, we shall follow the syntatic style of the Report, as we already did on some occasions, writing for instance "reference-to-reference-
to-MODE-identifier". We do so just to point out that for these "notions" exist certain production rules in the syntax, by which they are defined. ultimately as sequences of symbols. You can have some confidence that the intuitive meaning of these notions is in good accordance with their syntactic coherence and the meaning imposed upon them by the semantics of the language. Certain parts of notions are written in capital letters. For such "metanotions" exist separate metaproduction rules, defining them in terms of other notions. Some of these metanotions stand for an infinite number of other notions, which is the case with "MODE". Some others cover only a finite number.

There is no reason to worry about the syntax, but in the long run you might appreciate our attempts to break you softly to the syntactic saddle and the metanotional stirrups of the Report.

In this informal Introduction "amode" stands for "a mode" (you may conceive amode as a declarer for some, not specified, MODE). We shall also use indications like bmode, umode, zmode. For all these declarers you may substitute any MODE-declarer derived from the primitives, with the assistance of the symbols:

<table><tr><td>ref</td><td>(1.2.2)</td></tr><tr><td>proc</td><td>(1.2.3 and 4.2.1)</td></tr><tr><td>struct</td><td>(Sections 1.4.1 and 2.4.1)</td></tr><tr><td>"[" and "]"</td><td>(Sections 1.5.1 and 2.5.1)</td></tr><tr><td>union</td><td>(Sections 1.6.1 and 2.6.1)</td></tr><tr><td>long and short</td><td>(Sections 1.7.1 and 2.7.2)</td></tr></table>

We have already met *marilyn* and her sisters *mar1,2,3lyn* who all yield *ref amode* objects. We shall soon meet also their cousins *mar u lyn mar v lyn* and other *mar*-vellous ladies. However, we shall in the sequel substitute for *amode* other declarers (even *ref amode*), and all the girls will then follow the new fashions. We trust that you will recognise them in their other moods.

### 1.2.3.1. proc modes

In this section we consider the case in which we substitute for *amode* the declarer of a procedure with parameters delivering a value or not. We mainly do so to elucidate further the principle of identity, which is the main subject of 1.2. A more complete discussion of declarations in which procedures are involved will be found in 4.2.

All values of mode PROCEDURE are routines. A routine is the internal equivalent of the sequence of symbols which comprises some routine-text. In
a call this routine is activated. In a routine we can make use of formal-parameters; the actual-parameters are then supplied when the routine is called. It is not without reason that the LHS of an identity-declaration is denominated as the "formal-parameter", and the RHS as the "actual-parameter". The fact is that the identity-declaration states very precisely what happens when an actual-parameter is supplied, be it in a procedure call or in a formula.

A routine can be denoted by a routine-text, in much the same way as, for instance, "true" may denote the value of this sentence. In the denotation of a routine with formal-parameters we find the formal-PARAMETERS-pack, a sequence of formal-parameters separated by commas ",".

Declarers for procedures with parameters (see also 4.2.1) have the form:

<table><thead><tr><th>not returning a useful value:</th><th>returning a zmode value:</th></tr></thead><tbody><tr><td>proc ( umode ) void</td><td>proc ( umode ) zmode</td></tr><tr><td>proc ( umode , vmode ) void</td><td>proc ( umode , vmode ) zmode</td></tr><tr><td>proc ( umode , vmode , wmode )</td><td>proc ( umode , vmode , wmode )</td></tr><tr><td>void</td><td>zmode</td></tr></tbody></table>

etc.

etc.

We now reconsider:

(E1) amode thing = marllyn ;

We take for amode the declarer:

(E8.1) proc ( umode , vmode ) zmode

and for marllyn the routine-text:

(E8.2) ( umode u , vmode v ) zmode: XXXXX

in which we find the formal-PARAMETERS-pack ( umode u , vmode v ), corresponding to the ( umode , vmode ) in E8.1.

We thus obtain the identity-declaration:

(E8) proc ( umode , vmode ) zmode thing = ( umode u , vmode v ) zmode: XXXXX ;

This, however, seems to contain some redundancy, and it may therefore be replaced by the contracted form:

(E8*) proc thing = ( umode u , vmode v ) zmode: XXXXX ;
The result of the elaboration of the 'routine-identity-declaration' E8* is that (a copy of) the routine E8.2 is ascribed to *thing*. Observe that the XXXXX is not elaborated at this stage. The result of the elaboration of E8* may be depicted as below:

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

#### 1.2.3.2.1. The supply of the actual parameters (call by value)

Calling the *thing* of E8*, we have to supply an actual-umode-parameter and an actual-vmode-parameter. Let *mar u lyn* be a *umode* variable and *mar v lyn* a *vmode* variable. If we now "parametrize" *thing* by writing the actual-PARAMETERS-pack (*mar u lyn*, *mar v lyn*) right behind *thing*, we obtain the procedure call:

(E9) `thing (mar u lyn, mar v lyn)`

To elaborate this, we must first do some transformation of the routine (E8.2) yielded by *thing*:

(E8.2*) `zmode (umode u = ~, vmode v = ~; XXXXX)`

The "~"s are only there as locum tenens for the actual-MODE-parameters; we will now get rid of them by replacement with the corresponding actual-parameters.

The result is the cast:

(E10) `zmode (umode u = mar u lyn, vmode v = mar v lyn; XXXXX)`

This cast is then elaborated, yielding a *zmode* value which is then the value returned by the call:
<figure><img src="image_41.png" /></figure>

If, for instance, *mar z lyn* is declared to be a *zmode* variable, then you may assign:

(E9*) $\mathit{mar\ z\ lyn} := \mathit{thing} ( \mathit{mar\ u\ lyn} , \mathit{mar\ v\ lyn} )$

which, in fact, elaborates into:

(E10*) $\mathit{mar\ z\ lyn} := \mathit{zmode} ( \mathit{umode\ u} = \mathit{mar\ u\ lyn} , \mathit{vmode\ v} = \mathit{mar\ v\ lyn} ; XXXXX )$

### 1.2.3.2.2. The supply of the actual parameters (call by reference)

Observe that in E10 you cannot assign to the formal-parameters *u* and *v*; the identity-declarations in E10 are of type E1; *u* and *v* are constants, copies of the values referred to by *mar u lyn* and *mar v lyn* respectively. This situation has some similarity to “call by value” in some other programming languages.
If you want to assign a formal-parameter, you have to declare it to be a reference-to-MODE; the replacement action then leads to an identity-declaration of type E2 (equivalence, two names referring to the same instance of a value).

Consider, for example, the procedure declaration:

(E11) proc ( ref zmode , umode , vmode ) void assign thing = ( ref zmode z , umode u , vmode v ) void: z := XXXXX

or, contracted:

(E11*) proc assign thing = ( ref zmode z , umode u , vmode v ) void: z := XXXXX ;

The call:

(E12) assign thing ( mar z lyn , mar u lyn , mar v lyn )

elaborates into:

<figure><img src="image_42.png" /></figure>
The call E12 is equivalent to the cast:

$$ (E12*) \quad \begin{array}{l} \texttt{void (ref zmode z = mar z lyn, umode u = mar u lyn,} \\ \qquad \texttt{vmode v = mar v lyn; z := XXXXX)} \end{array} $$

It is important to observe that the first identity-declaration is of the type E2. Its effect is that, by its elaboration, a copy of the name yielded by the actual-parameter *mar z lyn* is ascribed to the formal-parameter *z*. The result is that *z* and *mar z lyn* both refer to the same *zmode* value. Consequently, assignation to *z* within the routine has the same result as assignation to *mar z lyn*. This is exactly what we wanted to achieve.

Conforming to the domesticated terminology of a "call by value", we might refer to the elaboration of a reference-to-MODE-parameter as a "call by reference".

The second and third declarations ascribe constants to *u* and *v*, copies of the values referred to by *mar u lyn* and *mar v lyn* respectively; these actual-parameters are "called by value".

### 1.2.3.2.3. The supply of the actual parameters (other possibilities)

Now we know exactly what happens to the actual-parameters in a procedure call, we shall find no difficulties in other applications of the principle of identity. For example:

Suppose you want to call *assign thing*, but you are only interested in the elaboration of the routine (for its side effects, for instance) but not in the implied assignation to the first parameter. Then you may call:

$$ (E13) \quad \textit{assign thing (loc zmode, mar u lyn, mar v lyn)} $$

which elaborates into:

$$ (E13*) \quad \begin{array}{l} \texttt{void (ref zmode z = loc zmode, umode u = mar u lyn,} \\ \qquad \texttt{vmode v = mar v lyn; z := XXXXX)} \end{array} $$

and see what happens. The first identity-declaration is now of type E3; a variable of local scope is ascribed to *z*. The value in which you were not interested is assigned to this local variable and disappears when the elaboration of the routine is completed.

Suppose the value of, for instance, *mar v lyn* does not matter under some circumstances, and you have no *vmode* value at hand in the range where you want to call *assign thing*. Then you may call:

$$ (E14) \quad \textit{assign thing (mar z lyn, mar u lyn, skip)} $$
Now, when this call is elaborated, the textually third “~” in the transformed routine is replaced by **skip**. A **skip** happens to be a very docile little dud: it always delivers an undefined value of the required mode without any further action.

### 1.2.4. Summary

For their importance in this language, we review briefly the constructions E1, ---, E6. Ascribe them to identifiers in your own memory:

<table><thead><tr><th>recommended form:</th><th></th><th>extended form :</th><th></th></tr></thead><tbody><tr><td>amode <i>thing</i> = marllyn;</td><td>amode <i>thing</i> = marllyn</td><td></td><td>(E1)</td></tr><tr><td>ref amode <i>name</i> = marllyn;</td><td>ref amode <i>name</i> = marllyn</td><td></td><td>(E2)</td></tr><tr><td>loc amode <i>aname</i>;</td><td>ref amode <i>aname</i> = loc amode</td><td></td><td>(E3)</td></tr><tr><td>loc amode <i>aname</i> := marllyn;</td><td>ref amode <i>aname</i> = loc amode := marllyn</td><td></td><td>(E4)</td></tr><tr><td>loc ref amode <i>pointer</i>;</td><td>ref amode <i>pointer</i> = loc ref amode;</td><td></td><td>(E5)</td></tr><tr><td>loc ref amode <i>pointer</i> := marllyn;</td><td>ref amode <i>pointer</i> = loc ref amode := marllyn</td><td></td><td>(E6)</td></tr></tbody></table>

where the locs in the left hand column may be omitted.

And remember:

(E1) *thing* does not yield a name and you cannot assign to it (provided, however, that **amode** does not happen to be a mode-indication for a **ref bmode**).

(E2) *name* yields the same name as *marllyn*; assignation to *name* has the same result as assignation to *marllyn* and vice versa.

(E3) *aname* yields a new name, different from all other names (that is what the local-generator achieves) and you can assign to it.

(E4) *aname* yields a new name (variable) and is initialized by assigning the value referred to by *marllyn* to it.

(E5) *pointer* yields a reference to a name (a variable name or name of a name); you can assign a name to it.

(E6) *pointer* yields a reference to a name and is initialized to refer to the name yielded by *marllyn*.

Vertical readers, please turn to 2.2.
## 1.3. Symbols, modes and operators

### 1.3.1. Representations

A 'program' is defined to be a sequence of 'symbols'. Consider for example:

```
begin real x, y, z;
    read (x); read (y); x := abs x; y := abs y;
    z := (x + y)/2 - sqrt(x * y);
    print (z)
end
```

This piece of program begins with the symbol "begin" followed by the sequence "real" "x" "," "y" "," "z" "," "read" "(" "x" ")" "," and so on. Typographical display features, such as blank space, change to new line, and change to new page have no significance in the language. Strictly speaking "begin", "real", "x", "," etc. are not themselves symbols; they rather represent them.

In the Report the representation(s) of symbols is strongly recommended, rather than explicitly prescribed. For the benefit of available charactersets, other representations may be chosen for a specific implementation of the language; one and the same implementation might even accept different representations from different input-devices. The given piece of program could for example look like:

```
'BEGIN' 'REAL' X, Y, Z;
    READ(X); READ(Y); X := 'ABS' X; Y := 'ABS' Y;
    Z := (X + Y)/2 - SQRT(X * Y);
    PRINT(Z)
'END'
```

or even:

```
.BEGIN .REAL X, Y, Z;
    READ(X); READ(Y); X := .ABS X; Y := .ABS Y;
    Z := (X+Y)/2 - SQRT(X*Y);
    PRINT(Z)
.END
```

On the other hand, if small letters and capitals are both available, one could for instance reserve the capitals for the construction of representations
for special symbols such as the begin-symbol, the real-symbol etc. If suitable tokens are available one could also choose other representations for the go-on-symbol and the becomes-symbol and the example might then look like:

```
BEGIN REAL x, y, z ⇒
    read(x) ⇒ read(y) ⇒ x ← ABSx ⇒ y ← ABSy ⇒
    z ← (x + y)/2 - sqrt(x × y) ⇒
    print(z)
END
```

In this Informal Introduction we shall always follow the recommendations of the Report [see R 9.4]. Where the Report suggest alternatives, we shall follow our own taste which may, however, depend upon the context. A complete list of the alternatives recommended by the Report is given in Appendix 1 and a particular recommended standard is given in Appendix 5.

### 1.3.2. Symbols, bold words and comments

In this language a rather extensive set of symbols is required, and moreover, we need some expedient for constructing an arbitrary number of new symbols.

A decisive point of course is the set of characters, types and marks producible by your input equipment; or, to state it more precisely, distinguishable by the input devices on your computer. If this happens to be you, then there is hardly any problem, thanks to the productive power of human handwriting and the perceptive qualities of the human eye. With an automaton there may, however, be some difficulty. Usually its senses are only able to distinguish a rather small set (some power of two) of different combinations of punched holes or magnetized spots in some material. In that binary form usually at least one font of letters (we represent them in lower case), ten digits, the punctuation marks ".", "," ":" "", "" and "’", one pair of brackets "(" and ")" and a more or less generally accepted set of marks, such as "+", "-", "x" (or "*"), "/" and "=", can be represented. In more favourable cases, the equipment may afford more luxury in the form of a second case of letters and/or some selection of types such as "<", ">", "[", "]", "V", "^" and perhaps even "_", "↑", "'0" etc. In particular an underlining "_" and a vertical stroke "|" may be available and can be used to assist in the construction of other tokens like, for instance, "‡", "≤", "≥" etc.

Nevertheless, this language needs much more than all the marks
mentioned, and thus, even for the representation of the finite set of required symbols, an expedient to construct symbols from available marks appears to be essential. The Report recommends [R 9.4.2.2.b] that the extra symbols, or "bold words", be constructed similarly to identifiers, but distinguished from them by means of a "stropping" convention. The strop mechanism may be open- and close-apostrophes, or a period used as "boldface shift", or underlining, or bold type face, or the use of upper case letters (i.e. the capitals):

"begin" is an identifier or 'tag' (see 1.4)

but:

"'begin'", "begin", "begin", "begin" or "BEGIN"

might be used as a stropped word to represent the begin-symbol.

Here we adopt stropping by bold type face. In this notational convention, a sequence of marks like "notification" is to be considered as one indivisible symbol and definitely not as a sequence of the symbols "not", "if", "i", "c", "at", "i" and "on", even though "not", "if", "i" and "at" happen to be proposed representations for required symbols, and "c" and "on" very well might be operators or mode-indications. Whether you want to consider such a construct as an ill chosen representation (in particular if such a splitting happens to make sense) or not is related to your inclination to meditate on problems concerning the amount of blank paper needed to separate spots of ink. Anyhow, you will be wasting your time, because the Report dictates [R 9.4.2.2.b] that, even though blank space, change to a new line and the like normally have no meaning in this language, you must use them to resolve this ambiguity by writing **not** if i c at i on if that is what you really want. Otherwise, the bold word **notification** is to be assumed.

We are thus able to construct as many symbols as we need. For example "isn't" for ":±:" and "at" for "@" if we are unable or unwilling to produce or use ":±:" and "@" on our input equipment. In particular we are now in the position to introduce as many bold words as we want, and we really need them for:

1) MODE-mode-indications (see 1.3.3.1)

for example we used **amode** as an amode-mode-indication

2) operators (see 1.3.3.2 and 3)

For the representation of an operator, it will be appropriate to use "+", "x", "^" etc. if the action defined can be considered as an "addition",
"multiplication" or "conjunction" in some technical sense. Moreover, composite symbols such as $+x$, $>=$, $+:=$, $\div x$:= are admissible [R 9.4.2.1]. For the rest we shall use bold words for operators as well.

A particular role is played by the comment-symbol represented by "comment", "co", "#" or "†" and also, for special purposes, by "pr" or "pragmat". These symbols serve to step outside the language for a while.

A 'comment' consists of two matched comment-symbols enclosing an arbitrary sequence of characters, marks and types, not containing that comment-symbol. Thus comment *this is a comment* and co ¢ co are comments, but co *this is not a comment* ¢ is not. Comments can be inserted at any place in a program except inside an identifier, a bold word or a denotation (5.1.1.1 and 5.5.1.1).

A specific implementation may distinguish human comments, between two comments or ¢s, from pragmats between two pragmats or prs.

A (human) comment then serves to supply additional human information for the possibly human reader.

A pragmat may contain a message for a specific compiler (for instance to inform it to compile in some special mode or sub-language or to subjoin the program to some library or something), or for an operating system (for instance to inform it concerning certain required equipment or availability of hardware features, certain libraries etc.). A pragmat will usually be subject to the rules of a specific command language.

Consider the following program:

```
pr ALGOL68 pr
begin comment this example is based on the revised
        report on the algorithmic language
        algol68 section 9.2; end of comment
        proc pr NONREC pr pr = void: pr;
        pr
        comment if NONREC means "nonrecursive compilation",
                   whatever that may be, then we got into
                   trouble comment
        end pr RUN pr ¢ ??? ¢
```

In the standard-prelude (the standard declarations) of the Report a special comment-symbol "c" is used to express that the so called "pseudo-comment" should be replaced by a representation of a declarer or closed-clause suggested by that comment [R 10.1.2 Step 7]. In this Informal Introduction we shall follow this convention (e.g. in 3.7.2.E5).
### 1.3.3. Other declarations

Besides the identifier-declarations (1.1.2) we have:

1) mode-declarations (1.3.3.1)

2) operation-declarations (1.3.3.2)

3) priority-declarations (1.3.3.3).

#### 1.3.3.1. Mode-declarations

A mode-declaration has the form:

`mode MODE-mode-indication = actual-MODE-declarer`

For example, in:

(E1) `mode pram = proc / umode, vmode / zmode;`

the pram-mode-indication pram is declared to stand for the actual-declarer, which is `proc / umode, vmode / zmode`, and now, by declaring for example:

(E2) `loc pram puvz;`

you ascribe to *puvz* a name referring to a value of the mode *pram*, which is a routine with a *umode* and a *vmode* as parameters, returning a *zmode* value:

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

We may now assign to the procedure variable *puvz*, for example:

(E3) *puvz* := *thing*

where *thing* is declared as in 1.2.3.1.E8 to yield a `proc / umode, vmode / zmode`. What happens in the elaboration of E3 is:
<figure><img src="image_44.png" /></figure>

In fact we are now repeating the things we discussed in 1.2.

By virtue of the mode-declaration E1, the variable-declaration E2
“develops” into:

(E2*) `loc proc` `/ umode`, `/ vmode` `/ zmode` `puvz`;

“to develop” is a technical term, which should be distinguished from
“to elaborate”.

In “elaboration” actions on internal objects are performed.

In “development”, a mode-indication is replaced by its actual-declarer.

(One could say that “elaboration” is performed by the object code (at run
time), while “development” is an action of the compiler.)

(In E3 the semantics of the lanugage state that the **pram** yielded by *thing*
is copied into the **pram** referred to by *puvz*. As in other situations where
copying is prescribed, one should remember an important remark in Section
2.1.4.1.a of the Report: "Any of these actions ... may be replaced by any
action ... which causes the same effect". In particular where routines are
manipulated, the implementor usually has other expedients at his disposal
which "cause the same effect" as copying. The same applies to many other
situations of this kind, particularly where copying might appear to be
involved.)

You may declare a mode-indication as a convenient abbreviation for
certain declarers (as, for instance, was the case in E1 and E2). You could do
without them in these situations, at the price of time and ink.

There are, however, very interesting and important situations in which
mode-declarations are indispensable for expressing certain essential
interrelations of objects in the memory. Some of these more involved mode-declarations will be used in other sections (see 1.4).

Circular mode-declarations like:

`mode amode = amode;`

`mode amode = bmode; mode bmode = cmode;`

`mode cmode = amode;`

`mode amode = ref amode;`

might bring the compiler into difficulties and are apparently of no use. Consequently, they are regarded as not well-formed (2.4.3). However, there are constructions which might puzzle you at first sight, because they have an appearance of circularity (in fact are circular in some aspect), but nevertheless are very useful and can (easily) be implemented. Of course, such mode-declarations are well-formed and are not excluded.

### 1.3.3.2. Operation declarations

There are two kinds of operators: monadic, declared as:

(E4) `op ( umode ) zmode m = ( umode u ) zmode: XXXXX;`

or, by contraction:

(E4*) `op m = ( umode u ) zmode: XXXXX;`

and dyadic, declared as:

(E5) `op ( umode , vmode ) zmode ⋄ = ( umode u , vmode v ) zmode: XXXXX;`

or, by the same contraction:

(E5*) `op ⋄ = ( umode u , vmode v ) zmode: XXXXX;`

Observe the resemblance to procedure declarations. Instead of declarers like `proc ( umode ) zmode` and `proc ( umode , vmode ) zmode` we have here `op ( umode ) zmode` and `op ( umode , vmode ) zmode`.

The result of the elaboration of an operation-declaration is that (a copy of) the routine is ascribed to the operator. For example, E5 (E5*) elaborates into:
<figure><img src="image_45.png" /></figure>

In contrast to procedures, an operator can only be defined to yield a
routine and not to refer to one. Consequently, the uncontracted forms (as in
E5) are rarely of practical use, and we shall never write one again.

If *mar z lyn* is declared to be a *zmode* variable, then the assignation:

(E6) $mar\ z\ lyn := mar\ u\ lyn \diamond mar\ v\ lyn$

elaborates into:

(E6*) $mar\ z\ lyn := zmode(\ umode\ u = mar\ u\ lyn, \ vmode\ v = mar\ v\ lyn; XXXXX)$

The cast in E6* is then elaborated, yielding a *zmode* value which is
returned by the formula:

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

Observe that this picture is almost identical to the picture of Section
1.2.3.2.1.
There is, however, a fundamental contradistinction to procedures. For one and the same operator more than one declaration may occur within the same range. Which one then applies depends entirely on the mode(s) of the operand(s) in the particular formula in which the operator is applied.

For example:

(E7) op m = ( amode a ) amode: XXXXX ;

(E8) op m = ( bmode b ) bmode: WWWWV ;

(E9) op ◊ = ( amode a1, a2 ) amode: XXXXXX ;

(E10) op ◊ = ( bmode b1, b2 ) bmode: XXXXX ;
amode am, am1, am2 ; bmode bm, bm1, bm2 ;

am1 := m am2 ; ⇒ E7 applies

bm1 := m bm2 ; ⇒ E8 applies

am := am1 ◊ am2; ⇒ E9 applies

bm := bm1 ◊ bm2 ⇒ E10 applies

Observe that it is determined during the compilation of the formula which operator, i.e. which routine, applies.

### 1.3.3.3. Priority declarations

All monadic-operators have the same, the highest, priority.

For dyadic-operators nine priority levels can be declared by a priority-declaration of the form:

prio ◊ = DIGIT-token

in which "DIGIT-token" produces one of the nine digits "1" to "9".

In a formula with dyadic-operators of equal priority like:

(E11) am ◊ am1 ◊ am2 ◊ am

the implied bracketing is:

(E11*) (( am ◊ am1 ) ◊ am2 ) ◊ am

Priority-declarations may impose another (implied) bracketing:

(E12) prio o = 6, ◊ = 7, x = 8 ;

the bracketing implied in the formula:

(E13) a × b ◊ c × d ○ e ◊ f ○ g × h ◊ i × j × k ○ l
is:

(E13*) `(( (a × b) ◊ (c × d)) ○ (e ◊ f) ) ○ ((g × h) ◊ ((i × j) × k) ) ) ○ l`

Unless explicit bracketing requires otherwise, monadic-operators are
elaborated first, i.e. they have the highest priority:

(E14) `am := m am1 ◊ m am2`

is parsed like:

(E14*) `am := ( m am1 ) ◊ ( m am2 )`

Of course it would have been possible (and in fact has been investigated)
to declare different priority levels for different monadic-operators. However,
it makes matters very awkward without much gain. The main root of this
smallness of gain is that, if m1, m2, ..., mn were monadic-operators with
different priorities, nevertheless only one parsing is conceivable for the
formula m1 m2 ... mn operand, Namely:

( m1 ( m2 ( --- ( mn operand ) --- ) ) )

The gain can thus be found only in combination with dyadic-operators. There
is only one situation in which you might feel sorry (see 5.1.3).

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

1.4. Stowed values, structures

1.4.0. STOWED values

In this language values (one or more) can be STOWED (i.e. collected) to
form a value of a new mode. The metanotion "STOWED" stands for:

1) ‘structured with FIELDS mode’

or

2) ‘ROWS of MODE’

corresponding to two entirely different systems of collecting:

1) into a "structured value" (this section)

2) into a "multiple value" (section 1.5).
In a multiple value you collect values of essentially the same mode, its "elements", each of which can be selected by a specific set of subscripts. The mode of a multiple value is 'ROWS OF MODE' and covers the concept of "array" (or "vector", "matrix", "dimension", etc.) in other programming languages.

In a structure you collect values of (not necessarily) different modes, the "fields" of the structure, each of which can be selected by a specific field-selector. Structured values cover what in other programming languages are known under a variety of names like "records", "lists", "trees", "queues", "chains", etc.

The important feature of structures is that values of different modes may be collected into them. In particular, one or more of the fields may be references to other values, in which way lists and trees of all kinds may be constructed.

Another important feature, however, is that the selection of a field in a structure may very well take place at compile time, whereas the subscripts of an element in a multiple value are usually determined (computed) at run time. Therefore, even in situations in which multiple values are the only possibility in many other programming languages, in this language you will often use structures instead. A good example is the compl (see Section 2.4.4).

Finally, the general concept of MODE allows you to build multiple values the elements of which are structures, and vice versa to build structures the fields of which are multiple values.

### 1.4.1. Enumeration by tagging

By a mode-declaration like:

(EO) **mode triple** = struct(*umode first*, *vmode second*, *wmode third*);

**triple** is declared to "specify" a new class (mode) of values, each of which is structured with three fields, a **umode** field *first*, a **vmode** field *second* and a **wmode** field *third*. *first*, *second* and *third* are the 'field-selectors'.

Syntactically a field-selector is a sequence of letters and digits with a leading letter. It may look like an identifier but it is not. It is important to recognize clearly its function:

* A field-selector as such does not yield any internal object.

* A field-selector is part of a declarer or of a selection.

* A **triple** object, as declared by EO, may be visualized as a box with a **umode**, a **vmode** and a **wmode** box within it, the fields of the **triple**. These
fields can be "pulled up" by their field-selectors *first*, *second* and *third*. We might imagine a piece of cord between the field and its tag:

triple

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

It is important to bear in mind that *first*, *second* and *third* are not names referring to the fields (see 1.4.1.1).

Merely to simplify our drawings we shall often write the selectors inside the boxes:

triple

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

warning :

our drawings serve to visualize internal objects and matters of elaboration;

please do not confuse the selector in the box with the instance of a value in it.

### 1.4.1.1. Structured constants

We now reconsider the three fundamental identity-declarations E1, E2 and E3 of Section 1.2, in which we substitute systematically **triple** (as declared in E0) for **amode**:

(E1) triple thing = marllyn ;
By E1, a copy of the **triple** value referred to by *mar1lyn* (which is itself of mode **ref triple**) is ascribed to *thing*:

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

After this declaration *thing* yields a **triple** object and its fields can be selected separately by pulling them up by their tags:

<table><tr><td><em>first</em> of <em>thing</em></td><td>selects</td><td>the <em>umode</em> object,</td></tr><tr><td><em>second</em> of <em>thing</em></td><td>selects</td><td>the <em>vmode</em> object,</td></tr><tr><td><em>third</em> of <em>thing</em></td><td>selects</td><td>the <em>wmode</em> object.</td></tr></table>

Because *thing* does not refer to a **triple**, you cannot assign to it.

Consequently you cannot assign to its fields *first of thing*, *second of thing* and *third of thing*, which in their turn yield the fields of *thing*.

In the declaration E1, *mar1lyn* is dereferenced, because *thing* is required to be of **triple** mode, and its fields are copied into the **triple** *thing* thus defined; the supersession is a triple action (three fields are copied). But, in the reach of this declaration, whatever may happen to the fields of the **triple**
referred to by *mar1lyn*, nothing can happen to the fields of the **triple** yielded by *thing*. You may select them, you cannot change them; *first of thing* etc. are not names.

### 1.4.1.2. Names of structures

By the declaration:

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

*mar1lyn* is not dereferenced (see 1.2.E2) as in E1, because the formal-parameter requires a **ref triple** value.

Clearly, *name* is a name, referring to the same **triple** object as *mar1lyn* (two identifiers referring to the same internal **triple**).

You may assign to *name*, for example:

(E2*)

`name := mar2lyn`

by which assignation the **triple** object referred to by *mar2lyn* is copied into the **triple** object referred to by *name* (and by *mar1lyn*).
Moreover you can assign to the names:

first of name , second of name and third of name .

For example, the assignation E2* is equivalent to the collateral assignation:

(E2**) ( first of name := first of mar2lyn ,
second of name := second of mar2lyn ,
third of name := third of mar2lyn )

Recapitulating:

first of thing , second of thing and third of thing
yield the fields of the triple yielded by thing ,

but:

first of name , second of name and third of name
yield names which refer to the fields of the triple referred
to by name . These are known as the "subnames" of name .

1.4.1.3. Creation of new structures

A new triple variable can be declared (see 1.2.E3) by means of a local-generator:

(E3) ref triple atriple = loc triple ;

or by the more usual variable-declaration:

(E3*) triple atriple; or loc triple atriple;

What happens is essentially the same as in 1.2.E3**:

<figure><img src="image_51.png" /></figure>
Of course you can also initialize a thus declared new triple:

(E4) ref triple *atriple* = loc triple := *mar1lyn*;

or more usually:

(E4*) triple *atriple* := *mar1lyn*;

You are not required by the syntax to declare a new mode like triple (E0) before you give identifier-declarations; that is, you may very well declare:

(E3**) struct ( umode *first*, vmode *second*, wmode *third*) *atriple*;

In most cases, however, you will spare time and ink by a mode-declaration. Moreover, if you use structures to construct lists etc., the mode-declaration is indispensable (see 1.4.3).

### 1.4.2. Different objects in one box

The fields of a structure may be of different modes, but could also be the same. In the latter case it is often a matter of efficiency (or even convenience) whether you declare them in a structure or in a multiple value. You can stow as many values in a structure as you wish, but you have to enumerate them in the declaration by tagging the fields explicitly. The number of fields in a structure is determined statically (at compile time). The minimum number is one, the maximum depends only on your perseverance in writing them down.

Of course the field-selectors in one structure must all be different. However, if it suits you, you may very well use the same sequence of symbols as a field-selector in different structures or even elsewhere as an identifier.

Just to give you some impressions, consider:

(E5) mode threeofakind = struct ( amode *one*, *two*, *three* );

which is a contraction of:

(E5*) mode threeofakind = struct ( amode *one*, amode *two*, amode *three* );

And consider further:

(E6) mode couple = struct ( man *one*, wife *two* );

(E7) mode largebox = struct ( amode *one*, *two*, *three*,
                       bmode *first*, *second*, *third*, *fourth*,
                       *fifth*, *sixth*,
```
cmode a, b, c, d, e, f, g, h, i, j, k,
l, m, n, o, p, q, r, s, t, u,
v, w, x, y, z);
```

Now consider the variable-declarations:

(E8)
threeofakind one, two, three, four, five, six, seven, eight;
couple romeo and juliet, tristan und isolde,
daphnis et chloe;
largebox a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r,
s, t, u, v, w, x, y, z;

and observe that there are no ambiguities in:

(E9)
*one of two, two of three, one of one,*
*two of romeo and juliet, one of daphnis et chloe,*
*one of t, t of t, o of o, a of b,*
etc.

There is no restriction on the modes of the fields in a structure; every
mode is allowed (including structures, see 1.4.4). Consider, for example:

(E10)
mode surprisepacket =
    struct ( umode umode, vmode vmode, zmode zmode,
             proc ( ref zmode, umode, vmode ) void proc );

and the variable-declaration:

(E11)
surprisepacket s1, s2, s3;

and the assignations:

(E12)
*umode of s1 := mar u lyn;
vmode of s2 := mar v lyn;
proc of s := assign thing;

By virtue of E11, *proc of s* is a procedure variable, a reference to a *proc (ref zmode, umode, vmode) void* to which we assign in E12 the compatible routine yielded by *assign thing* (see 1.2.E11*). If we now parametrize *proc of s* (1.2.3.2.1), it will be dereferenced to yield a routine which can be called (this will be discussed in 4.2.2.2). For reasons to be discussed later (5.5.1.3.E30) we must put brackets around *proc of s* before parametrizing it.

Now you may fish out what happens by elaboration of the call:

(E13)
(*proc of s*) ( zmode of s3, umode of s1, vmode of s2 )
### 1.4.3. Chaining

By declaring a field of a structure to refer to (to be the name of) another value, you can chain this structure to that other value. If, in particular, this other value is of the same mode as the structure, we are able to chain values of the same mode (i.e. to construct "queues", "lists", "trees" etc.).

Consider:

(E14) `mode box = struct / amode value, ref box next);`

This mode-declaration is one of those which have an appearance of circularity (see 1.3.3.1). You might think that it develops into:

```
mode box = struct / amode value,
          ref struct / amode value,
          ref struct / amode value,
          ref struct / etc. ad infinitum
```

This, however, is not the case. The box textually contained in `ref box next` in E14, is "shielded" by the `struct` and the `ref` (see 2.4.3 for the details). Therefore the compiler does not develop box (in this syntactic position).

Consider the identity-declarations:

(E15) `box a, b, c, d;`

The result of their elaboration will be:

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

Observe that the field tagged `next` is of the same mode as the name ascribed to `a`, `b`, etc. There is not a tittle of infinity about the size of these boxes.
Let us first assign:

$$
\begin{align*}
\text{(E16)} \quad \mathit{value \ of \ a} &:= \mathit{mar1lyn} ; \\
\mathit{value \ of \ b} &:= \mathit{mar2lyn} ; \\
\mathit{value \ of \ c} &:= \mathit{mar3lyn} ; \quad \mathit{mar3} \text{ and } \mathit{4lyn} \text{ are ref amodes} \\
\mathit{value \ of \ d} &:= \mathit{mar4lyn} ; \quad \text{like their sisters (see 1.1.2.2).}
\end{align*}
$$

Because *a* refers to a box, *value of a* is the subname referring to its *amode* field. Consequently, *value of a* yields a *ref amode* value and thus is an *amode* variable, which is why we can assign *mar1lyn* to it. The four *mar* *lyn* are dereferenced and their *amode* values are copied into the *value of* fields of the boxes referred to by *a*, *b*, *c* and *d* respectively.

Much more interesting is to see what happens when we assign:

$$
(E17.1) \quad next \ of \ a := b ;
$$

By the same reasoning as above, *next of a* is the subname referring to the
*ref box* field of the *box* referred to by *a*. Consequently, *next of a* yields a *ref*
*ref box* value and thus is a *ref box* variable (is a variable name) (see also
5.4.2). Therefore *b* in the RHS of the assignation is not dereferenced and the
value yielded by *b* is copied into the field *next* of the *box* referred to by *a*:

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

The result is that we have chained the box referred to by *a* to the box
referred to by *b* via the *next* of field of the box *a*.
Similarly:

(E17.2) next of b := c ;

(E17.3) next of c := d ;

Finally, we want to express that *d* is the last box in the chain. Then we must give a special value to its *next of* field, recording this fact. Such a value is *nil*, which is "a name referring to no value":

(E17.4) next of d := nil ;

What we have achieved by the assignations E17 is:

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

Let us now consider the assignation :

(E18) value of next of next of next of a := marilyn

next of a refers to b,
next of b refers to c,
next of c refers to d,

consequently, *value of next of next of next of a* refers to the **amode** field of
the **box** referred to by *d*. It thus appears that E18 was a rather complicated
way of prescribing:

(E18*) value of d := marilyn

In a mode as declared in E14 we can build single threaded lists. Of course
we can chain in much more complicated ways.

For example:

(E19) mode node = struct ( amode mainvalue ,
                          proc ( amode ) amode function ,
                          ref node north , east , south , west );

(E20) node p, q, r, s, t, u, v, w;

We may assign:

(E21) mainvalue of p := marilyn ;
etc.
function of p := ( amode a ) amode: XXXXX;
etc.

(E22) north of p := q ; east of p := r ; south of p := s ; west of p := t ;
north of r := u ; east of r := v ; south of r := w ; west of v := r ;
north of s := p ; east of t := p ; south of q := p ; west of u := q ;
north of w := r ; east of q := u ; south of u := r ; west of r := p ;
east of s := w ; west of w := s ;

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

You might now like to meditate on expressions like:
(E23) function of w := ( amode a ) amode:
    if mainvalue of w = a
    then mainvalue of north of w
    else (function of v) (mainvalue of east of w)
        fi

1.4.4. Pandora's boxes

A field of a structure may be another structure with a field which may be
another structure and so on:

(E24) mode pandora = struct ( amode a , pando p );

(E25) mode pando = struct('amode', pan, 'p');

(E26) mode pan = struct('amode', ref pandora next);

By virtue of E25 and E26, E24 develops into:

(E24*) mode pandora = struct('amode a',
                       struct('amode a',
                       struct('amode a',
                       ref pandora next
                       )p
                       )p
                       );

Intentionally, we chose the selectors of the fields of **pandora** and its inner
fields somewhat confusingly, just to point out that such is allowed (though it
may not be wise).

(E27) pandora p;

Now observe that:

a of p refers to an amode value,

a of p of p refers to an amode value,

a of p of p of p refers to an amode value,

but:

a of p of p of p of p is meaningless

as are:

next of p because a pandora has no next of field,

next of p of p because a pando has no next of field,
but:

next of *p* of *p* of *p* refers to a pandora

as do also:

next of *p* of *p* of next of *p* of *p* of *p*,

next of *p* of *p* of next of *p* of *p* of next of *p* of *p* of *p*, etc.

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

The well-formed rule (2.4.3) prohibits circular definitions like:

mode pandoravel = struct('amode', pandoravel.p);

Here pandoravel is not shielded by a ref. The compiler cannot do anything sensible with this pandoravel. Obeying such a mode-declaration would result in an endless loop of development.
Observe that, as soon as a **ref** stands in front of some declarer, the only thing the compiler has to do is (to be prepared) to reserve a location for holding a name; that is why a declarer following a **ref** in a **struct** can be shielded.

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

## 1.5. Stowed values, multiples

### 1.5.1. Multiple values and descriptors

A multiple value (or "multiple" for short) consists of:

1) zero, one or more values, all of the same mode.

These values are the "elements" of the multiple. Each element is selected by a set of one or more integers, its "subscripts". In this section, we use *h*, *i*, *j*, *k*, *m*, *n*, *m1*, *n1*, ... as units yielding an integral value.

2) a "descriptor".

A descriptor describes the subscripts that are required to select an element—how many of them are needed and what bounds are to be set on their values.

Examples of the modes of multiple values are:

**[ ] amode [, ] amode [,, ] amode [,,] amode**

which should be pronounced as 'row of amode', 'row row of amode', 'row row row of amode' and so on, or, in general, as some 'ROWS OF MODE' where "ROWS" stands for as many times 'row' as you may require. The number of 'row's in the mode is the number of subscripts needed to select an element, and "MODE" (amode in the examples) specifies the mode of each element.

Syntactically, **[ ] amode**, **[, ] amode**, etc. are formal-ROWS-of-MODE-declarers (you can use them in formal-parameters). Actual-ROWS-of-MODE-declarers (for use in generators and therefore also in variable-declarations) are more complex, since they must contain the descriptor of the value to be generated. Here are some examples:

<table><tr><td>[m : n] amode</td><td>¢ one 'row' in the mode ¢</td></tr><tr><td>[k : k, m : n] amode</td><td>¢ two 'row's in the mode ¢</td></tr><tr><td>[m1 : n1, m2 : n2, m3 : n3] amode</td><td>¢ three 'row's in the mode ¢</td></tr></table>
and even

`[k:k] [m:n] amode`

¢ one 'row', but the 'MODE' also has a
'row' in it, giving 'row of row
of amode' ¢

$m:n, k:k, \text{etc. are "boundpairs"; } [k:k, m:n] \text{ specifies the complete descriptor. Each boundpair consists of a lower-bound (to determine the lowest acceptable subscript), a colon, and an upper-bound (to determine the highest acceptable subscript). If the upper-bound of any boundpair is lower than the corresponding lower-bound, then the descriptor is "flat" and the multiple value consists of zero elements.}$

We shall bring multiple values into our pictures in the following way:

`[] amode`

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

It is important to realize that the
descriptor belongs to the multiple value.
You even have a certain access to it (see
1.5.5).

`[,] amode`

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