Beginner

Variables and Types in ALGOL 60

Learn about variables, data types, and type declarations in ALGOL 60 with practical Docker-ready examples

ALGOL 60’s type system was genuinely revolutionary for 1960. At a time when FORTRAN distinguished INTEGER from REAL mostly by name convention, ALGOL 60 introduced a formal, compiler-enforced static type system with explicit declarations. Every variable must be declared before it is used, the compiler knows each variable’s type at compile time, and mixing incompatible types is a compile error — concepts that became the backbone of Pascal, C, Ada, and virtually every statically-typed language that followed.

ALGOL 60 defines three core scalar types: integer (whole numbers), real (floating-point numbers), and Boolean (logical true/false values). Strings in GNU MARST are handled as literals for output; the language was not originally designed around string manipulation. ALGOL 60 also supports arrays — including the groundbreaking innovation of arrays with runtime-computed bounds — which were a major departure from the fixed-dimension arrays of FORTRAN.

Because ALGOL 60 is an imperative, procedural, structured language, its variables work exactly as you would expect from that paradigm: you declare them, assign them values, reassign them, and they exist for the lifetime of the enclosing block. There is no type inference, no dynamic typing, and no garbage collector — variables are stack-allocated within their lexical scope.

Declaring Integer and Real Variables

All variable declarations appear at the top of a block, before the first executable statement. This separation between declarations and executable code is one of ALGOL 60’s defining structural features — a convention that Pascal and Ada preserved directly.

Create a file named variables.alg:

begin
  integer count, max_size, negative;
  real pi, temperature, ratio;

  comment Assign integer values;
  count    := 42;
  max_size := 1000000;
  negative := -17;

  comment Assign real values;
  pi          := 3.14159;
  temperature := 98.6;
  ratio       := 2.71828;

  comment Output integer values;
  outstring(1, "=== Integer Variables ===\n");
  outstring(1, "count     = "); outinteger(1, count);     outstring(1, "\n");
  outstring(1, "max_size  = "); outinteger(1, max_size);  outstring(1, "\n");
  outstring(1, "negative  = "); outinteger(1, negative);  outstring(1, "\n");

  comment Output real values;
  outstring(1, "\n=== Real Variables ===\n");
  outstring(1, "pi          = "); outreal(1, pi);          outstring(1, "\n");
  outstring(1, "temperature = "); outreal(1, temperature); outstring(1, "\n");
  outstring(1, "ratio       = "); outreal(1, ratio);       outstring(1, "\n")
end

A few things to notice here:

  • integer and real are type keywords — lowercase, no stropping needed in GNU MARST
  • Multiple variables of the same type are listed after the type keyword, comma-separated
  • := is the assignment operator; = is used only for equality comparison
  • Declarations come before the first statement — you cannot declare in the middle of a block
  • The last statement in a block does not end with a semicolon (semicolons are separators, not terminators)

Boolean Variables and Logical Expressions

ALGOL 60 introduced Boolean as a first-class type, named after the mathematician George Boole. Boolean values are true and false (lowercase in GNU MARST), and the logical operators are (and), (or), and ¬ (not) in the original report. GNU MARST uses ASCII alternatives: and, or, not, = (equivalence), and or imp (implication).

Create a file named variables_bool.alg:

begin
  Boolean is_active, is_done, result;
  integer x, y;

  is_active := true;
  is_done   := false;
  x         := 10;
  y         := 20;

  comment Boolean expressions using comparisons;
  result := x < y;

  outstring(1, "=== Boolean Variables ===\n");
  outstring(1, "is_active = "); outstring(1, if is_active then "true" else "false"); outstring(1, "\n");
  outstring(1, "is_done   = "); outstring(1, if is_done   then "true" else "false"); outstring(1, "\n");
  outstring(1, "x < y     = "); outstring(1, if result    then "true" else "false"); outstring(1, "\n");

  comment Logical operators;
  outstring(1, "\n=== Logical Operations ===\n");
  outstring(1, "true and false = ");
  outstring(1, if true and false then "true" else "false"); outstring(1, "\n");
  outstring(1, "true or false  = ");
  outstring(1, if true or false  then "true" else "false"); outstring(1, "\n");
  outstring(1, "not true       = ");
  outstring(1, if not true       then "true" else "false"); outstring(1, "\n");

  comment Integer arithmetic in context;
  outstring(1, "\n=== Integer Arithmetic ===\n");
  outstring(1, "x + y = "); outinteger(1, x + y); outstring(1, "\n");
  outstring(1, "x * y = "); outinteger(1, x * y); outstring(1, "\n");
  outstring(1, "y / x = "); outinteger(1, y / x); outstring(1, "\n");
  outstring(1, "y - x = "); outinteger(1, y - x); outstring(1, "\n");

  comment Power operator uses double star ** in MARST;
  outstring(1, "x ** 2 = "); outinteger(1, x ** 2); outstring(1, "\n")
end

The if ... then ... else ... construct used inside outstring calls is ALGOL 60’s conditional expression — an expression that yields a value based on a Boolean condition. It is not a statement; it produces a result that can be used anywhere an expression is valid. This feature predates the ternary operator ? : that C borrowed for the same purpose.

Arrays in ALGOL 60

Arrays are one of ALGOL 60’s most celebrated features. Unlike FORTRAN, which required array sizes to be known at compile time, ALGOL 60 allowed array bounds to be computed at runtime — a radical innovation in 1960. Arrays are declared with the array keyword followed by a subscript range.

Create a file named variables_arrays.alg:

begin
  integer n, i, sum;
  real average;
  integer array scores[1:5];

  comment Initialize array elements;
  n        := 5;
  scores[1] := 85;
  scores[2] := 92;
  scores[3] := 78;
  scores[4] := 95;
  scores[5] := 88;

  comment Calculate the sum;
  sum := 0;
  for i := 1 step 1 until n do
    sum := sum + scores[i];

  comment Calculate average - promote sum to real before dividing;
  average := (sum + 0.0) / n;

  outstring(1, "=== Array Example ===\n");
  outstring(1, "Scores: ");
  for i := 1 step 1 until n do
  begin
    outinteger(1, scores[i]);
    if i < n then outstring(1, ", ")
  end;
  outstring(1, "\n");

  outstring(1, "Sum     = "); outinteger(1, sum);     outstring(1, "\n");
  outstring(1, "Average = "); outreal(1, average);    outstring(1, "\n")
end

Key array facts in ALGOL 60:

  • integer array scores[1:5] declares an integer array with indices 1 through 5 (1-indexed by convention, though any integer range is valid)
  • Array element assignment and access use [ and ] brackets
  • The type keyword (integer, real, Boolean) precedes array to specify element type; bare array without a type defaults to real
  • Use integer array or real array to declare typed arrays explicitly

Type Conversion Between Integer and Real

ALGOL 60 requires explicit awareness of integer versus real arithmetic. Division of two integers performs integer division (truncation toward zero). Mixing an integer and a real in an expression typically promotes the result to real. When you need to convert between types explicitly, you can use arithmetic tricks or rely on the type coercion rules.

Create a file named variables_types.alg:

begin
  integer a, b, int_result;
  real x, y, real_result;

  a := 7;
  b := 2;
  x := 7.0;
  y := 2.0;

  comment Integer division truncates;
  int_result := a / b;

  comment Real division gives fractional result;
  real_result := x / y;

  outstring(1, "=== Type Behavior ===\n");
  outstring(1, "a        = "); outinteger(1, a);           outstring(1, " (integer)\n");
  outstring(1, "x        = "); outreal(1, x);              outstring(1, " (real)\n");

  outstring(1, "\n=== Division Results ===\n");
  outstring(1, "7 / 2 (integer) = "); outinteger(1, int_result);  outstring(1, "\n");
  outstring(1, "7.0 / 2.0 (real) = "); outreal(1, real_result);   outstring(1, "\n");

  comment entier() converts real to integer (floor function);
  real_result := 3.75;
  outstring(1, "\n=== entier() Function ===\n");
  outstring(1, "entier(3.75) = "); outinteger(1, entier(real_result)); outstring(1, "\n");
  outstring(1, "entier(-3.75) = "); outinteger(1, entier(-real_result)); outstring(1, "\n");

  comment Integer value used in real context - automatically widened;
  real_result := a;
  outstring(1, "\n=== Widening ===\n");
  outstring(1, "integer a = "); outinteger(1, a); outstring(1, "\n");
  outstring(1, "as real   = "); outreal(1, real_result); outstring(1, "\n")
end

The entier() function is the ALGOL 60 standard way to convert a real to an integer — it computes the floor (greatest integer not exceeding the value). Assigning an integer expression to a real variable widens the value automatically.

Running with Docker

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Pull the ALGOL 60 image
docker pull codearchaeology/algol60:latest

# Run the basic variables example
docker run --rm -v $(pwd):/app -w /app codearchaeology/algol60:latest algol60-run variables.alg

# Run the Boolean and arithmetic example
docker run --rm -v $(pwd):/app -w /app codearchaeology/algol60:latest algol60-run variables_bool.alg

# Run the arrays example
docker run --rm -v $(pwd):/app -w /app codearchaeology/algol60:latest algol60-run variables_arrays.alg

# Run the type conversion example
docker run --rm -v $(pwd):/app -w /app codearchaeology/algol60:latest algol60-run variables_types.alg

Expected Output

Output from variables.alg:

=== Integer Variables ===
count     = 42
max_size  = 1000000
negative  = -17

=== Real Variables ===
pi          = 3.14159
temperature = 98.6
ratio       = 2.71828

Output from variables_bool.alg:

=== Boolean Variables ===
is_active = true
is_done   = false
x < y     = true

=== Logical Operations ===
true and false = false
true or false  = true
not true       = false

=== Integer Arithmetic ===
x + y = 30
x * y = 200
y / x = 2
y - x = 10
x ** 2 = 100

Output from variables_arrays.alg:

=== Array Example ===
Scores: 85, 92, 78, 95, 88
Sum     = 438
Average = 87.6

Output from variables_types.alg:

=== Type Behavior ===
a        = 7 (integer)
x        = 7 (real)

=== Division Results ===
7 / 2 (integer) = 3
7.0 / 2.0 (real) = 3.5

=== entier() Function ===
entier(3.75) = 3
entier(-3.75) = -4

=== Widening ===
integer a = 7
as real   = 7

Key Concepts

  • Declarations precede statements — All variables must be declared at the top of a block, before any executable code. This separation is structural and enforced, not a convention.
  • Three core scalar typesinteger, real, and Boolean cover the fundamental data needs ALGOL 60 was designed for: numeric computing and logical decision-making.
  • := is assignment, = is equality — The distinction between := (gets the value of) and = (is equal to) was introduced by ALGOL 60 and carried forward into Pascal, Ada, and Modula-2. C chose = for assignment instead, creating decades of confusion.
  • Integer division truncates — Dividing two integer values performs truncation; use real variables for fractional results.
  • entier() is the floor function — ALGOL 60 provides entier(x) to convert a real to its integer floor; this is the standard way to convert from real to integer.
  • Dynamic array bounds — ALGOL 60 was the first major language to allow array bounds computed at runtime, a significant advance over FORTRAN’s compile-time-only arrays. Bounds are written as [lower:upper].
  • Conditional expressions return valuesif B then E1 else E2 is an expression, not just a statement. It evaluates to either E1 or E2 based on B, allowing it to appear anywhere a value is needed.
  • Lexical scope by block — Variables are scoped to the begin...end block in which they are declared. Nested blocks can declare their own variables that shadow outer ones — the lexical scoping rules that became standard in virtually all modern languages.

Running Today

All examples can be run using Docker:

docker pull codearchaeology/algol60:latest
Last updated: