Seed7 - The extensible programming language
Seed7 FAQ Manual Screenshots Examples Libraries Algorithms Download Links
Manual Introduction Tutorial Declarations Statements Types Parameters Objects File System Syntax Tokens Expressions OS access Actions Foreign funcs Errors
Tutorial Hello world Local decls For loop Parameters Decl stat Template
Manual
Tutorial
 previous   up   next 

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

s7 hello

The Seed7 interpreter writes something like

SEED7 INTERPRETER Version 5.0.4  Copyright (c) 1990-2013 Thomas Mertes
hello world

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

hello world

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

s7 -q hello

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-statement 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 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.4 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 compile time error:

*** tst77.sd7(5):52: 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 compile time error

*** tst77.sd7(12):52: 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.5 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.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 library forloop.s7i.


 previous   up   next