Defining Routines

General Routines

There are two types of routine: Functions and Shapes ( the Program routine is effectively a Shape but with restrictions on the formal parameters ). These types of routine have a lot in common so will be dealt with together. The term routine will apply to both; when discussing features that apply to just one, the term function or shape will be used as appropriate.

functdef ::= [ scope ] Function type routname ( [ formallist ] ) body ;

shapedef ::= [ scope ] Shape routname ( [ formallist ] ) body ;

formallist ::= formal [[ , formal ]]

formal ::= [ Const ] [ Ref ] type parmname [ = expr ]

body ::= locals Begin stmtblock End ;

locals ::= [[ localdatdecl ]]

The scope specifies the visibility of the function and has the same options and syntax as for global data. The default scope for routines is Private.

The type specifies the return type of the function or the type of a formal parameter, and must be the name of a type current in scope when the function is defined. A Shape does not return a value so does not have a return type.

The routname is the name which will be use to call the routine. It should not clash with a name already in the global name scope.

The formallist is the list of formal parameters for the routine ( the term 'formal' is used in the definition of the routine; the term 'actual' is used when calling the routine ).

Each formal parameter specification consists of an optional constant property, Const; an optional reference property, Ref; and a type and parmname, and an optional initialisation expression. Note the type and name are the only two components that are obligatory.

The parmname is a standard identifier, but by convention is usually lower case. The parameter names are in the local scope of the routine and will not clash with names in other routines. If a name clashes with a global name in scope then the parameter name effectively hides the global use of the name.

The localdatdel is discussed on the chapter concerning datums. The names of the local variables are all in the scope of the routine and must not clash with each other or with a formal parameter name.

Function Routines

A function routine is a routine that returns a value. Therefore the routine definition requires a return type to be specified. All execution paths must end in a Return statement with an expression that yields a value of that type.

A function does not have a graphics context and cannot call shape routines. It is possible to have graphics context objects as a parameters ( in which case it is recommended that they are passed as Const Ref parameters ).

Private Function Number Squared(Number x)
	Number result;
    Begin
	result := x;
	result *= x;
	Return result;
    End;

Shape Routines

A shape routine does not return a value, therefore the definition does not contain a return type.

The statement block can contain any statements ( but the Return statement cannot have a return expression ). There is a implicit Return statement at the end of the routine. It is possible to have other Return statements to cause early termination of the routine.

Private Shape BarredCircle(Number radius, Logical nobar = False)
    Begin
	Circle(radius);
	If nobar Then
		Return;
	EndIf;
	Line( {-radius, 0}, {radius, 0} );
    End;

The Program Routine

The Program routine is like a shape routine except the Shape keyword is omitted.

There are also limitations on the types of the parameters. Only Number, Logical, Text and enumerated types may be specified. Parameters cannot be marked as Ref. Then final parameter may be a one dimensional open array of one of the permitted types.

Reference Parameters

Normally when a value is passed to a routine a copy of the actual parameter data is placed in the private memory space of the called routine. This means that any changes to the value will not affect any values in the calling routines. This is known as 'call by value'. This is safe but for a large data objects, such as a large array, this would be inefficient in terms of execution time and memory usage.

It is possible to tell the system to use the actual data block within the calling routine. This is known as 'call by reference' and is flagged with the Ref keyword in the formal parameter declaration.

Constant Parameters

Any datum can be flagged as constant to warn programmers that they are trying to modify something they should not. For a routine reference parameter this will also ensure that the caller's data will not be altered. To flag a parameter as constant use the Const keyword - if used in conjunction with the Ref keyword the Const should come first.

Default Expressions

It is possible to define a default value for a parameter that will be used if the caller does not supply that parameter in the call. Note: the default value will not be used if the caller explicitly set the actual parameter to Null.

The default value can be specified using the option "= expr" in the formal specification. The expression can only use values that are declared at the global level. The result will be calculated with the values at the time the routine is called.

Initialising Local Variables

A local variable can be initialised with an expression. Normal datums ( i.e. those not flagged as saved ) can use global values, parameter values and other locals that have already been declared. These are evaluated each time the routine is called.

Saved Local Datums

A local datum can be given the attribute Saved. This means that the value can be saved between calls. The value can be initialised with an expression that uses just global values. The initialisation is done just one when the program starts running.