Home Up Intro Contents Chapter 1 2 3 4 5 6 7 8 9 10 Design Assert Timing EBNF Report Pas Last Changed: July 12th, 1997
This is a conversion from Oberon text to HTML, and from German to English. The converter software is still under development, and some features or information may be missing in this converted version. HTML hypertext facilities are not yet active in this document. To exploit the interactive facilities, use Oberon System 3 and the source of this text, available for download using binary ftp as Oberon System 3 archive. The converter from German to English is still under development as well. A previous version is also available for Oberon V4. To access this and other additional material use ftp.
For the convenience of our students, most of this information and the related material is available in German as well.

Introduction to Oberon

The Oberon Programming Language

G. Sawitzki <gs@statlab.uni-heidelberg.de>



07 Procedures, Functions

Modules can be structured by procedures and functions. A procedure groups statements in a block and makes this group available under a name, which is used to activate it. A procedure is introduced by a procedure declaration. Beside the block of statements, a procedure may also contain formal parameters and local declarations A procedure is called by its name, possibly followed by a current parameter list.

As for all declarations an export mark can be attached to procedure declarations. The usual rules apply: within the module, in which the procedure is defined, a procedure is called by its name is called. If it is to be called in another module, the module in which the procedure is defined must be imported, and the procedure is called by its qualified name module name.Procedure name.

Procedure Call:
    procedure name [current parameter list]
Current Parameter List:
    ( [Parameter {, Parameter }] )

We already met procedure calls. The statement System.Time calls procedure Time in module System. This is a parameterless procedure. The statement Texts.WriteString(w, 'Hello') calls the procedure WriteString in module Texts. Two parameters are transferred: the Writer w and the stringer 'Hello'. Parameters can be transferred in two ways. For parameters like the string in this example the value (in this case 'Hello') must be actually transferred. If the current parameter is an expression, the expression is evaluated first and the result is passed as parameters, for example when calling Texts.WriteInt(w, i+j, 10). For other parameters like the Writer w, a reference only needs to be transferred. The called procedure is to actually operate on the current Writer, possibly changing it.

The procedure declaration determines which parameters are transferred by value and which are transferred by reference. Parameters which are transferred by reference are marked by VAR. In a procedure call these must be represented by a variable. Parameters which are not marked VAR are passed by value. Constants or expressions can be used as current parameters as well as variables. Implicitly a local variable is generated for each value parameter. This is visible only within the procedure and it is only valid there. The current parameters are evaluated upon procedure call and the result is transferred in this implicit local variable.

Procedure Syntax:
  PROCEDURE [target] procedure name [formal parameter list];
Declaration sequence
  [BEGIN
    statement sequence ]
  END
procedure name;

Formal Parameter List
( [ formal parameter {; formal parameter } ] )[ : type of result ]
Formal Parameter
[ VAR ] name {, name}: Type


For Texts.WriteString and Texts.WriteInt, the declaration headings are given in the module Texts as
  PROCEDURE WriteString*(VAR W: Writer; s: ARRAY OF CHAR);
  PROCEDURE WriteInt*(VAR W: Writer; x, n: LONGINT);

With the procedure call the current parameters are assigned to the formal parameters by position. With value parameters, the appropriate current expressions are evaluates and the results are assigned to the respective formal parameters, which then act as local variable. The current parameter list must correspond to the formal list.

Oberon-2 extends the Oberon syntax by the target, an optional parameter. The target is inserted in front of the procedure name. The target is treated in a special way for support of a particular programming style, object oriented programming. We come back to this issue in a later chapter.

The declaration section of a procedure essentially corresponds to that of a module. Declarations from a procedure however cannot be exported - only declarations in the outermost level can be exported. Procedures define local visibility and ranges of validity. The range of validity begins with the place of the declaration and extends at the end of the procedure. Names may be used only within the range of validity of their declaration. No name may refer to more than one object within its range of validity. The range of validity can be nested however: a (sub)procedure defines a new range of validity. If a name is defined which is defined already in the surrounding block, the local declaration applies up to the end of the procedure; hence the previous becomes invisible until the end of the local block. In contrat to this, global variables of a module persist until the module is unloades explicitly.

A procedure can contain more than one RETURN statement. Procedures can have result type; if so, they are called function procedures if it is necessary to distinguish them from ordinary procedures. Functional procedures must always be left with a RETURN statement. With functional procedures, an expression which is compatible with the type of result must follow the RETURN statement. This expression is evaluated and the result is passed as result of the functional procedure.
RETURN Statement
  RETURN
{ expression }

Example
  PROCEDURE MIN( a,b:REAL): REAL;
  BEGIN
    IF a<b THEN RETURN a ELSE RETURN b END
  END MIN;

A procedure can be called in its own statement part. This leads then to a recursion. As a notation. this is usually a very compact representation. As executable instruction, this usually implies overhead: a procedure call means that working space has to be allocatd and space must be supplied for local variable, control needs to be transferred, and a secured return to the calling statement must be prepared. Usually this is more complex this than a sequential execution of statements. If recursions can be avoided, this should be done. In particular a recursion can be avoided whenever it is called as the last statement of an statement sequence.



Exercises:

1.) In many program libraries there are procedures to calculate power function. How would you program a functional procedure XPwrI, for x>=0, i>=0 to calculate the power xi.
  PROCEDURE XPwrI(x:LONGREAL; i:LONGINT): LONGREAL;

2.) Implement the three generators from the previous chapter as function procedures RandLGM, RandPRB, RandUNIX and test these procedures.

3a.) Write a pseudo-random number generator, which simulates a uniform distribution on [ 0.1 ] using RandLGM. Implement this generator as function procedure.

3b.) Write a function procedure which produces pseudo-random numbers with exponential distribution, using the generator from 3a. The rate should be a parameter of the functional procedure.

4.) Simulate a simple queue with exponential arrival and service time. Simulate then the flow for 20 customers with a) arrival rate=service rate; b) arrival rate=service rate/2.

5.) Write a "pretty printer", which writes a real number in a convenient format for reading, where the format may be data dependent. Example:
  Value    Output
  0.0E0     0
  1.2E1     12
  1.2345E2  123.45
If you need special mathematical funtions, you will find most of what is neeeden in module Math. Hint: use a fixed width font to simpliy the task.


Exercises:
Compare the two following implementations of the factorial function. Which computational effort do they need?

PROCEDURE Fak1(i:INTEGER):LONGINT;
BEGIN
  ASSERT(i>=0);
  IF i<=1 THEN RETURN 1
  ELSE RETURN i*Fak1(i-1)
  END;
END Fak2;

PROCEDURE Fak2(i:INTEGER):LONGINT;
VAR res:LONGINT;
BEGIN
  ASSERT(i>=0);
  res:=1;   WHILE i>1 DO res:=res*i; DEC(i) END;
  RETURN res
END Fak2;



Several procedures are pre-defined in Oberon. You find a list of the pre-defined procedures in the Oberon report. The next source of available procedures are exported procedures in standard modules. Only the last resort is writing procedures yourselves.


Introduction to the Oberon programming language. ItO/Ch07.Text
gs (c) G. Sawitzki, StatLab Heidelberg
<http://statlab.uni-heidelberg.de/projects/oberon/intro/>

Home Up Intro Contents Chapter 1 2 3 4 5 6 7 8 9 10 Design Assert Timing EBNF Report Pas