Manual
Tutorial
 previous   up   next 

2. TUTORIAL

2.1 Hello world

Below is the hello world program of Seed7:

$ include "seed7_05.s7i";

const proc: main is func
  begin
    writeln("hello world");
  end func;

Save this program to the file hello.sd7 and start it in a console with:

s7 hello

The Seed7 interpreter writes something like

SEED7 INTERPRETER Version 5.1.790  Copyright (c) 1990-2023 Thomas Mertes
hello world

You get information about the Seed7 interpreter and the output of the hello.sd7 program:

hello world

The option -q can be used to suppress the information line of the Seed7 interpreter:

s7 -q hello

The first line of the program

$ include "seed7_05.s7i";

includes all definitions of the standard library. In contrast to other libraries the seed7_05.s7i library contains not only function declarations but also declarations of statements and operators. Additionally the seed7_05.s7i library defines the main function as entry point for a Seed7 program.

In the example above main is declared as constant and proc is the type of main. Declaring main with the type proc makes a procedure out of it. The object main gets a

func ... end func

construct as value. The 'func' construct is similar to begin ... end in PASCAL and { ... } in C. Inside the 'func' is a writeln statement with the "hello world" string. The writeln statement is used to write a string followed by a newline character.

2.2 Greeting

The program below starts a little dialog:

$ include "seed7_05.s7i";

const proc: main is func
  local
    var string: name is "";
  begin
    write("What's your name? ");
    readln(name);
    writeln("Hi " <& name <& "!");
  end func;

Save this program to the file greeting.sd7 and start it in a console with:

s7 greeting

The program asks you for your name with:

What's your name?

After you entered your name and pressed enter it will greet you. This program uses the variable 'name' to store the name you entered. Variables must be defined. The place to to define and initialize all variables of a function is after the keyword local.

var string: name is "";

This defines the string variable 'name'. This definition assigns also the initial value "" to 'name'. The value "" is the empty string (it contains no characters). In Seed7 variables must be defined and always get an initial value.

The write statement is similar to writeln, but it does not write a newline character. The readln statement reads a line from the standard input file and assigns this line to the given variable. This function allows the usage of backspace to correct the input. By pressing enter the line is sent to the program. The final writeln statement contains the operator <& to concatenate strings. If necessary the <& operator converts values to string.

The greeting program above has a problem. If someone refuses to type his name and just presses enter the program writes:

Hi !

To avoid this we improve the program to check for special cases:

$ include "seed7_05.s7i";

const proc: main is func
  local
    var string: name is "";
  begin
    write("What's your name? ");
    readln(name);
    if name = "" then
      writeln("Greetings to the person who pressed enter!");
    elsif name = "name" then
      writeln("Interesting, your name is name.");
    else
      writeln("Hi " <& name <& "!");
    end if;
  end func;

There can be zero or more elsif parts, and the else part is optional. As you can see the equality of strings is checked with =. The conditions of an if-statement decide what to do. By chance both conditions in the example above use the variable name. This special case opens the oportunity to use a case-statement instead:

$ include "seed7_05.s7i";

const proc: main is func
  local
    var string: name is "";
  begin
    write("What's your name? ");
    readln(name);
    case name of
      when {""}:
        writeln("Greetings to the person who pressed enter!");
      when {"name"}:
        writeln("Interesting, your name is name.");
      when {"Linus", "Torvalds"}:
        writeln("Are you the inventor of Linux?");
      otherwise:
        writeln("Hi " <& name <& "!");
    end case;
  end func;

As it can be seen, the keyword when is followed by a comma-separated list of values surrounded by braces. This is the set of values covered by this when-part. Depending on the value of 'name' one when-part is executed. If no when-part fits the otherwise-part is executed.

This is not the only way to improve the greeting program. Alternatively we can use a loop to insist on entering a name:

$ include "seed7_05.s7i";

const proc: main is func
  local
    var string: name is "";
  begin
    repeat
      write("What's your name? ");
      readln(name);
    until name <> "";
    writeln("Hi " <& name <& "!");
  end func;

The repeat ... until loop repeats the statements between the two keywords until the condition name <> "" is TRUE. Note that the statements in the repeat loop are executed at least once. A solution with a while loop is:

$ include "seed7_05.s7i";

const proc: main is func
  local
    var string: name is "";
  begin
    write("What's your name? ");
    readln(name);
    while name = "" do
      write("Just pressing enter is not okay. What's your name? ");
      readln(name);
    end while;
    writeln("Hi " <& name <& "!");
  end func;

The while loop repeats the statements between the keywords do and end as long as the condition name = "" is TRUE. Note that the statements in a while loop might not be executed at all. In the example above this happens if a non-empty name is entered after the question: What's your name?

2.3 Assignment

The following program writes the numbers from 1 to 10:

$ include "seed7_05.s7i";

const proc: main is func
  local
    var integer: count is 1;
  begin
    while count <= 10 do do
      writeln(count);
      count := count + 1;
    end while;
  end func;

This program declares a local variable of the type integer:

    var integer: count is 1;

The variable count above is initialized with 1. The value of a variable can be changed with an assignment (:=):

    count := count + 1;

The expression at the right of the := symbol is evaluated and assigned to the variable left of the := symbol. In the case above the variable count is incremented by one. For this special case there is a shortcut that could be used instead of the assignment:

    incr(count);

The output produced by this program is

1
2
3
4
5
6
7
8
9
10

What changes are necessary to count down from 10 to 0 instead?

2.4 Constants

To write a Fahrenheit to Celsius conversion table we use the following program:

(* Print a Fahrenheit-Celsius table
   for Fahrenheit values between 0 and 300 *)

$ include "seed7_05.s7i";

const proc: main is func
  local
    const integer: upper is 300;
    const integer: increment is 20;
    var integer: fahr is 0;
    var integer: celsius is 0;
  begin
    while fahr <= upper do
      celsius := 5 * (fahr - 32) div 9;
      writeln(fahr <& " " <& celsius);
      fahr +:= increment;
    end while;
  end func;

Everything between (* and *) is a comment, which is ignored. This program contains local constants and variables of the type integer. Constant declarations are introduced with const:

    const integer: upper is 300;
    const integer: increment is 20;

Like variables constants must be initialized with a value that is specified after the keyword is. Constants like upper cannot be changed. All constants just keep the initialization value. An attempt to change a constant results in a parsing error:

*** tst352.sd7(14):53: Variable expected in {lower := 10 } found constant integer: lower
    lower := 10;

Note that the error is reported before the program execution starts.

The program contains a while-statement and the expression to compute the 'celsius' value. The variable 'fahr' is incremented with the +:= operator. The statement:

      fahr +:= increment;

is a shortcut for the statement:

      fahr := fahr + increment;

The expression to compute the 'celsius' value uses an integer division (div). The output produced by this program is

0 -17
20 -6
40 4
60 15
80 26
100 37
120 48
140 60
160 71
180 82
200 93
220 104
240 115
260 126
280 137
300 148

2.5 For loop and float expressions

An improved version of the program to write the Fahrenheit to Celsius conversion table is:

# Print a Fahrenheit-Celsius table with floating point numbers.

$ include "seed7_05.s7i";  # This must be included first.
  include "float.s7i";     # Subsequent includes do not need a $.

const proc: main is func
  local
    const integer: lower is 0;
    const integer: upper is 300;
    const integer: increment is 20;
    var integer: fahr is 0;
    var float: celsius is 0.0;
  begin
    for fahr range lower to upper step increment do
      celsius := flt(5 * (fahr - 32)) / 9.0;
      writeln(fahr lpad 3 <& " " <& celsius digits 2 lpad 6);
    end for;
  end func;

Everything between # the end of the line is a line comment, which is ignored. To use the type float it is necessary to include float.s7i. The float variable 'celsius' must be initialized with 0.0 (instead of 0). The for-loop executes the loop body with different values of fahr (0, 20, 40 .. 280, 300). Omitting the step part corresponds to a step of 1:

for fahr range lower to upper do
  celsius := flt(5 * (fahr - 32)) / 9.0;
  writeln(fahr lpad 3 <& " " <& celsius digits 2 lpad 6);
end for;

The keyword downto can be used to run the for-loop backward:

for fahr range upper downto lower do
  celsius := flt(5 * (fahr - 32)) / 9.0;
  writeln(fahr lpad 3 <& " " <& celsius digits 2 lpad 6);
end for;

Since Seed7 is strong typed integer and float values cannot be mixed in expressions. Therefore the integer expression '5 * (fahr - 32)' is converted to float with the function flt. For the same reason a '/' division and the value '9.0' must be used. The <& operator is used to concatenate elements before writing. If the right operand of the <& operator has not the type string it is converted to a string using the 'str' function. The lpad operator converts the value of 'fahr' to a string and pads spaces to the left until the string has length 3. The digits operator converts the value of 'celsius' to a string with 2 decimal digits. The resulting string is padded left up to a length of 6.

2.6 Arrays

Arrays allow a variable to contain several values. E.g.: An array can be used to store a mapping from a day number to a day name:

$ include "seed7_05.s7i";

const proc: main is func
  local
    var array string: weekdayName is 7 times "";
    var integer: number is 0;
  begin
    weekdayName[1] := "monday";
    weekdayName[2] := "tuesday";
    weekdayName[3] := "wednesday";
    weekdayName[4] := "thursday";
    weekdayName[5] := "friday";
    weekdayName[6] := "saturday";
    weekdayName[7] := "sunday";
    for number range 1 to 7 do
      writeln(weekdayName[number]);
    end for;
  end func;

Since weekdayName is not changed after its values have been assigned, it can be declared as constant that is initialized with an array literal:

$ include "seed7_05.s7i";

const proc: main is func
  local
    const array string: weekdayName is [] ("monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday");
    var integer: number is 0;
  begin
    for number range 1 to 7 do
      writeln(weekdayName[number]);
    end for;
  end func;

The example above uses the array literal

[] ("monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday")

This array literal has the type array string and it is indexed beginning from 1. A corresponding array literal indexed beginning from 0 would be:

[0] ("monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday")

The for-loop above uses the literal 7 as upper bound. The function length can be used instead:

for number range 1 to length(weekdayName) do

This works as long as the array weekdayName is indexed beginning from 1. If this is not the case the functions minIdx and maxIdx can be used:

for number range minIdx(weekdayName) to maxIdx(weekdayName) do

For this case there is a convenient for-key-loop:

for key number range weekdayName do
  writeln(weekdayName[number]);
end for;

This for-key-loop loops over the indices of the array weekdayName (from 1 to 7). In the loop body the index is just used to access an element from the array. For this case there is a convenient for-each-loop:

$ include "seed7_05.s7i";

const proc: main is func
  local
    const array string: weekdayName is [] ("monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday");
    var string: name is "";
  begin
    for name range weekdayName do
      writeln(name);
    end for;
  end func;

A for-each-loop iterates over the elements of an array. Sometimes the elements and a corresponding index are needed. This is supported by the for-each-key-loop:

$ include "seed7_05.s7i";

const proc: main is func
  local
    const array string: weekdayName is [] ("monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday");
    var string: name is "";
    var integer: index is 0;
  begin
    for name key index range weekdayName do
      writeln("day " <& index <& ": " <& name);
    end for;
  end func;

Another example of a for-each-loop is:

$ include "seed7_05.s7i";

const proc: main is func
  local
    var integer: number is 0;
  begin
    for number range [] (0, 1, 2, 3, 5, 8, 13, 20, 40, 100) do
      write(number <& " ");
    end for;
    writeln;
  end func;

The example above uses the array literal

[] (0, 1, 2, 3, 5, 8, 13, 20, 40, 100)

This array literal has the type array integer. The index type of an array is not restricted to integers. A type like char, that has a 1:1 mapping to integer, can also be used as index:

$ include "seed7_05.s7i";

const proc: main is func
  local
    const array [char] string: digitName is
        ['0'] ("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine");
    var integer: number is 0;
    var char: ch is ' ';
  begin
    number := rand(1, 9999999);
    write(number <& ": ");
    for ch range str(number) do
      write(digitName[ch] <& " ");
    end for;
    writeln;
  end func;

The example above uses the array literal

['0'] ("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine")

This array literal has the type array [char] string. The minimum index of this array is the character '0'.

2.7 Hashes

A hash is similar to an array with the difference that the index can be any type (not just one that can be converted to integer). The type hash [string] integer defines a hash with a string as index and an integer as value. This type can be used in a type declaration:

const type: nameToDigitType is hash [string] integer;

A hash literal can be used to initialize hash constants or variables:

const nameToDigitType: nameToDigit is [] (
    ["zero" : 0], ["one" : 1], ["two"   : 2], ["three" : 3], ["four" : 4],
    ["five" : 5], ["six" : 6], ["seven" : 7], ["eight" : 8], ["nine" : 9]);

Like with arrays an element in the hash can be accessed with

nameToDigit[name]

The following example asks for digit names and writes the corresponding digit:

$ include "seed7_05.s7i";

const type: nameToDigitType is hash [string] integer;

const proc: main is func
  local
    const nameToDigitType: nameToDigit is [] (
        ["zero" : 0], ["one" : 1], ["two"   : 2], ["three" : 3], ["four" : 4],
        ["five" : 5], ["six" : 6], ["seven" : 7], ["eight" : 8], ["nine" : 9]);
    var string: name is "";
  begin
    write("Enter the name of a digit: ");
    readln(name);
    if name in nameToDigit then
      writeln("The value of " <& name <& " is " <& nameToDigit[name]);
    else
      writeln("You entered " <& name <& ", which is not the name of a digit.");
    end if;
  end func;

In the example above

name in nameToDigit

checks if the key name is in the hash table nameToDigit. This assures that getting the corresponding value with

nameToDigit[name]

succeeds. For-each loops can be used with hash tables as well. The example below uses keyDescription which is defined as hash [char] string in "keydescr.s7i". It contains descriptive texts for keyboard keys. A for-loop can loop over the values of a hash:

$ include "seed7_05.s7i";
  include "keydescr.s7i";

const proc: main is func
  local
    var string: description is "";
  begin
    for description range keyDescription do
      write(description <& " ");
    end for;
    writeln;
  end func;

A for-loop can also loop over the keys (indices) and values of a hash:

$ include "seed7_05.s7i";
  include "keydescr.s7i";

const proc: main is func
  local
    var char: aChar is ' ';
    var string: description is "";
  begin
    for description key aChar range keyDescription do
      writeln("const char: " <& description <& " is " <& literal(aChar));
    end for;
  end func;

2.8 For loop and containers

For-loops can also iterate over the elements of a set:

$ include "seed7_05.s7i";

const proc: main is func
  local
    var string: innerPlanet is "";
  begin
    for innerPlanet range {"Mercury", "Venus", "Earth", "Mars"} do
      write(innerPlanet <& " ");
    end for;
    writeln;
  end func;

In the example above {"Mercury", "Venus", "Earth", "Mars"} is a set literal. The type of this literal is set of string. Other set literals are:

{1, 2}
{'a', 'e', 'i', 'o', 'u'}

For-loops can iterate over the characters of a string:

$ include "seed7_05.s7i";

const proc: main is func
  local
    const set of char: vowels is {'a', 'e', 'i', 'o', 'u'};
    var char: letter is ' ';
  begin
    for letter range "the quick brown fox jumps over the lazy dog" do
      if letter not in vowels then
        write(letter);
      end if;
    end for;
    writeln;
  end func;

A for-loop can loop over the keys (indices) and values of a array:

$ include "seed7_05.s7i";

const proc: main is func
  local
    var integer: number is 0;
    var string: name is "";
  begin
    for name key number range [0] ("zero", "one", "two", "three", "four",
                                   "five", "six", "seven", "eight", "nine") do
      writeln(number <& ": " <& name);
    end for;
  end func;

All loops that iterate over a container can be combined with an until condition:

$ include "seed7_05.s7i";

const proc: main is func
  local
    var string: testText is "";
    var char: ch is ' ';
    var boolean: controlCharFound is FALSE;
  begin
    write("Enter text: ");
    readln(testText);
    for ch range testText until controlCharFound do
      controlCharFound := ord(ch) < 32;
    end for;
    if controlCharFound then
      writeln("The text contains control chars.");
    end if;
  end func;

2.9 Functions

The program below uses the function flipCoin to flip a coin until the result is heads:

$ include "seed7_05.s7i";

const func boolean: flipCoin is
  return rand(FALSE, TRUE);

const proc: main is func
  local
    var boolean: heads is FALSE;
  begin
    repeat
      write("Press enter to flip the coin. ");
      readln;
      heads := flipCoin;
      writeln(heads ? "heads" : "tails");
    until heads;
  end func;

In the example above, the function flipCoin is declared as constant. As const the code of flipCoin will not change during run-time. The type func boolean determines that the function returns a boolean value. The task of the function flipCoin is to return a random boolean value. This is done with:

return rand(FALSE, TRUE);

The actual random value is computed with the expression

rand(FALSE, TRUE);

The statement

heads := flipCoin;

assigns the result of flipCoin to heads. Afterwards heads is written with the ternary operator (?:). If heads is TRUE, it writes "heads" otherwise "tails".

The program below reads a multi-line paragraph:

$ include "seed7_05.s7i";

const func string: readMultiLineParagraph is func
  result
    var string: multiLineParagraph is "";
  local
    var string: line is "";
  begin
    repeat
      write("line: ");
      line := getln(IN);
      multiLineParagraph &:= line & "\n";
    until line = "";
  end func;

const proc: main is func
  begin
    writeln("Enter a multi line paragraph. An empty line ends the paragraph.");
    writeln("\nThe paragraph is:\n" <& readMultiLineParagraph);
  end func;

The declaration of readMultiLineParagraph above contains the construct:

func
...
end func

The function readMultiLineParagraph gets the func ... end func construct as value. This construct can be used to initialize functions and procedures. Note that proc is just a shortcut for func void and that void describes the empty type. Inside of the func ... end func construct are the keywords result, local and begin:

As can be seen from the function main above, the result and local parts are optional. If the function type is proc, the result part must be omitted. For all other functions the result part is mandatory.

2.10 Parameters

Most parameters are not changed inside a function. Seed7 uses 'in' parameters to describe this situation:

const func integer: negate (in integer: num1) is
  return -num1;

const func integer: fib (in integer: num1) is func
  result
    var integer: fib is 1;
  begin
    if num1 <> 1 and num1 <> 2 then
      fib := fib(pred(num1)) + fib(num1 - 2);
    end if;
  end func;

The functions above use 'in' parameters named 'num1'. An assignment to 'num1' is not allowed. A formal 'in' parameter like 'num1' behaves like a constant. Trying to change a formal 'in' parameter:

const proc: wrong (in integer: num2) is func
  begin
    num2 := 0;
  end func;

results in a parsing error:

*** tst77.sd7(5):53: Variable expected in {num2 := 0 } found parameter (in integer: num2)
    num2 := 0;

When a function wants to change the value of the actual parameter it can use an 'inout' parameter:

const proc: reset (inout integer: num2) is func
  begin
    num2 := 0;
  end func;

If you call this function with

reset(number);

the variable 'number' has the value 0 afterwards. Calling 'reset' with a constant instead of a variable:

reset(8);

results in a parsing error:

*** tst77.sd7(12):53: Variable expected in {8 reset } found constant integer: 8
    reset(8);

Sometimes an 'in' parameter is needed, but you need to change the formal parameter in the function without affecting the actual parameter. In this case we use the 'in var' parameter:

const func string: oct_str (in var integer: number) is func
  result
    var string: stri is "";
  begin
    if number >= 0 then
      repeat
        stri := str(number mod 8) & stri;
        number := number mdiv 8;
      until number = 0;
    end if;
  end func;

As you can see this works like a combination of an 'in' parameter with a local 'var'.

Conventionally there are two kinds of parameters: 'call by value' and 'call by reference'. When taking the access right (constant or variable) into account we get the following table:

parameter call by access right
val value const
ref reference const
in val / ref const
in var value var
inout reference var

Additionally to the parameters we already know this table describes also 'val' and 'ref' parameters which use 'call by value' and 'call by reference' and have a constant formal parameter. The 'in' parameter is called by 'val / ref' in this table which is easily explained:

An 'in' parameter is either a 'val' or a 'ref' parameter depending on the type of the parameter.

The parameter

in integer: number

is a 'val' parameter which could also be declared as

val integer: number

while the parameter

in string: stri

is a 'ref' parameter which could also be declared as

ref string: stri

The meaning of the 'in' parameter is predefined for most types. Usually types with small amounts of data use 'val' as 'in' parameter while types with bigger data amounts use 'ref'. Most of the time it is not necessary to care if an 'in' parameter is really a 'val' or 'ref' parameter.

In rare cases a 'ref' parameter would have undesired side effects with global variables or other 'ref' parameters. In these cases an explicit 'val' parameter instead of an 'in' parameter makes sense.

In all normal cases an 'in' parameter should be preferred over an explicit 'val' and 'ref' parameter.

2.11 Overloading

Functions are not only identified by identifiers but also via the types of their parameters. So several versions of a function can be defined:

$ include "seed7_05.s7i";
  include "float.s7i";
  include "bigint.s7i";
  include "bigrat.s7i";

const func float:       tenPercent (in float: amount)      is return amount / 10.0;
const func float:       tenPercent (in integer: amount)    is return float(amount) / 10.0;
const func bigRational: tenPercent (in bigInteger: amount) is return amount / 10_;

const proc: main is func
  begin
    writeln(tenPercent(123));
    writeln(tenPercent(123.0));
    writeln(tenPercent(123_));
  end func;

The example above defines the function tenPercent for the types float, integer and bigInteger. Two of these functions return a float and one returns a bigRational. This reuse of the same function name is called overloading. The literals 123, 123.0 and 123_ have the types float, integer and bigInteger respectively. This allows an easy identification of the tenPercent function used. Note that writeln is also overloaded. Otherwise writeln would not be able to accept float and bigRational arguments.

Overloading does not consider the result of a function. The following example attempts to overload addOne with the same parameter type and a different result type:

const func integer: addOne (in integer: num) is return num + 1;
const func float:   addOne (in integer: num) is return float(num) + 1.0;

Return type overloading is not supported. Therefore the attempt above results in the compile-time error:

*** tst344.sd7(5):34: Redeclaration of "addOne (val integer: num)"
const func float:   addOne (in integer: num) is return float(num) + 1.0;
------------------------------------------------------------------------^
*** tst344.sd7(4):35: Previous declaration of "addOne (val integer: num)"
const func integer: addOne (in integer: num) is return num + 1;

The absence of return type overloading improves readability, since:

 The type of every expression (and sub expression) is independent of the context.

You don't need to look where an expression is used. The expression alone gives you enough information to determine the type of the expression.

Operators like + can be overloaded with:

$ include "seed7_05.s7i";
  include "float.s7i";

const func float: (in integer: summand1) + (in float: summand2) is
    return float(summand1) + summand2;

const func float: (in float: summand1) + (in integer: summand2) is
    return summand1 + float(summand2);

const proc: main is func
  begin
    writeln(123 + 123.456);
    writeln(123.456 + 123);
  end func;

The definitions of the + operator above allow mixing of integer and float arguments. The overloaded + operators above are taken from the mixarith.s7i library.

2.12 Templates

Templates allow the declaration of functions where the actual types are specified later. The function declarations are done inside a procedure that has a type as parameter. E.g.:

const proc: DECLARE_MIN_MAX (in type: aType) is func
  begin

    const func aType: min (in aType: value1, in aType: value2) is
        return value1 < value2 ? value1 : value2;

    const func aType: max (in aType: value1, in aType: value2) is
        return value1 > value2 ? value1 : value2;

  end func;

The procedure DECLARE_MIN_MAX uses the type parameter aType to declare the functions min and max. The template must be instantiated for every actual type which needs min and max. E.g.:

DECLARE_MIN_MAX(integer);
DECLARE_MIN_MAX(bigInteger);
DECLARE_MIN_MAX(float);

This allows for expressions like min(2, 5) or min(PI, E).

2.13 Declare a statement

This example program writes its arguments

$ include "seed7_05.s7i";       # Standard Seed7 library

const proc: main is func
  local
    var string: stri is "";
  begin
    for stri range argv(PROGRAM) do
      write(stri <& " ");
    end for;
    writeln;
  end func;

The for-statement iterates over argv(PROGRAM). The function argv(PROGRAM) returns an array string (=array of string elements). The for-statement is overloaded for various collection types. In the standard Seed7 library seed7_05.s7i the for-statement for arrays is declared as follows:

const proc: for (inout baseType: variable) range (in arrayType: arr_obj) do
              (in proc: statements)
            end for is func
  local
    var integer: number is 0;
  begin
    for number range 1 to length(arr_obj) do
      variable := arr_obj[number];
      statements;
    end for;
  end func;

The syntax of this for-statement is declared as:

$ syntax expr: .for.().range.().to.().do.().end.for is              -> 25;

Additionally everybody can overload the for-statement also. Because of these powerful features Seed7 does not need iterators.

2.14 Template declaring a statement

Templates are just normal functions with types as parameters. The following template function declares for-statements:

const proc: FOR_DECLS (in type: aType) is func
  begin

    const proc: for (inout aType: variable) range (in aType: low) to (in aType: high) do
        (in proc: statements) end for is func
      begin
        variable := low;
        if variable <= high then
          statements;
          while variable < high do
            incr(variable);
            statements;
          end while;
        end if;
      end func;

  end func;

FOR_DECLS(char);
FOR_DECLS(boolean);

The body of the 'FOR_DECLS' function contains a declaration of the for-statement for the type aType. Calling 'FOR_DECLS' with char and boolean as parameter creates corresponding declarations of for-statements. The example above is a simplified part of the library forloop.s7i.


 previous   up   next