Seed7 
 FAQ 
 Manual 
 Screenshots 
 Examples 
 Algorithms 
 Download 
 Links 

 Manual 
 Introduction 
 Tutorial 
 Syntax 
 Statements 
 Types 
 Parameters 
 Objects 
 File System 
 Declarations 
 Tokens 
 Expressions 
 OS access 
 Actions 
 Errors 

2. TUTORIAL

We begin with a tutorial introduction to Seed7. In this chapter we want to show the principal ideas that make Seed7 work. At this point, we are not trying to be complete or precise. We just want to give a clear view to the primary philosophic ideas of Seed7. When the primary ideas are understood a complete and precise reference can be learned easier.

2.1 Hello world

A Seed7 program consists of a sequence of declarations. With each declaration a type and a name is attached to the new object. In addition every new declared object gets an initial value.

Here is an example of an object declaration:

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

The object '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. To use this declaration as the standard hello world example program, we have to add a few things:

    $ include "seed7_05.s7i";

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

The first line includes all definitions of the standard library. In contrast to other standard 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.

If you write this program in a file called hello.sd7 and execute the command

    hi hello

The Seed7 interpreter writes something like

    HI INTERPRETER Version 4.5.79  Copyright (c) 1990-2005 Thomas Mertes
       245 syntax.s7i
      2635 seed7_05.s7i
        33 hello.sd7
      2913 lines total
     29130 lines per second
    1184171 bytes
    hello world

You get information about the Seed7 interpreter, a list of libraries included and how many lines they contain, the number of bytes used by the hello.sd7 program and finally the output of the hello.sd7 program itself:

    hello world

2.2 Local declarations and expressions

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: lower is 0;
        const integer: upper is 300;
        const integer: increment is 20;
        var integer: fahr is 0;
        var integer: celsius is 0;
      begin
        fahr := lower;
        while fahr <= upper do
          celsius := 5 * (fahr - 32) div 9;
          write(fahr);
          write(" ");
          writeln(celsius);
          fahr := 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'. The constants and variables must be initialized when they are declared. This program contains also an assignment, a while loop and the expression to compute the 'celsius' value. Note that the statements inside the 'while' loop are between 'do' and 'end while'. The expression to compute the 'celsius' value uses an integer division ('div'). The 'write' statement can be used to write strings and integers without a newline character. 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.3 For loop and float expressions

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

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

    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;

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 is written as:

    for ... range ... to ... step ... do
      ...
    end for

To specify a lower and an upper limit together with a step value. For a step value of 1 the for loop it is written as:

    for ... range ... to ... do
      ...
    end for

And for a step value of -1 it can be written as:

    for ... range ... downto ... do
      ...
    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 'flt' function. 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.4 Parameters

Most parameters are not changed inside a function. To express this explicit Seed7 uses the 'in' parameter as in the following examples:

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

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

In both cases the formal parameter 'num1' is used in the function but no assignment is done to 'num1'. Inside the functions the parameter 'num1' behaves like a constant.

When a function should change the value of the actual parameter we can use the 'inout' parameter as in the following example:

    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. By the way, writing 'in' instead of 'inout' would have been illegal in the example above.

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: result is "";
      begin
        while number >= 0 do
          result := str(number rem 8) & result;
          number := number div 8;
        end while;
      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 this 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.5 Declare a statement

This example program writes it's 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 'argv(PROGRAM)' function 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 this powerful features Seed7 does not need Iterators.

2.6 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 standard Seed7 library "seed7_05.s7i".