At program start-up time, all objects are first initialized to the appropriate initial object. Next, the object expressions are evaluated in a compilation specific order. (Usually, the order that the modules are specified on the link command line.)
The language mandates the order of these clauses in order to improve uniformity between code.
For example:
procedure at_exit routine_types procedure exit_routine_type takes_nothing returns_nothing takes exit_routine exit_routine_type returns_nothing #: This procedure will register {exit_routine} #, to be called when the program is exiting.defines a procedure which takes as its only argument,
exit_routine
, a procedure variable that
will eventually be invoked upon exit. The signature
of the procedure variable is specified by the
routine_types clause to be a routine that
takes no arguments and returns no values.
The routine_types clause can reference any types imported into the module or defined within the module. In addition, for parameterized routines, the routine_types clause can reference any of the routine parameter types.
An example of a routine_types clause that references a parameter type is shown below:
procedure on_expose_set@window1[co_type] routine_types procedure expose_routine_type takes window, region, co_type returns_nothing takes window window expose_routine expose_routine_type returns_nothing #: This procedure stores the procedure variable #, to call when a region is exposed on {window}.In the example immediately above, the routine_types clause defines the
expose_routine_type
procedure
variable type whose third argument type is
the type co_type
, the parameter
name from window1[co_type]
.
For example, consider the code fragment that calls the procedure named add,
... x := add(y + 10, z - 17) ...where add is the following procedure:
procedure add takes a unsigned b unsigned returns unsigned return a + bThe procedure call sequence is equivalent to:
a := y + 10 b := z - 17where a and b are variables in the add procedure and x and y are evaluated in the environment at the call site.
variadic_clause --> variadic variadic_size_variable { [ variadic_parameter_name, ... ] } ø ¿ { variadic_name signature_type_reference }+ < { variadic_needs_clause } variadic_size_variable --> identifier variadic_parameter_name --> identifier variadic_name --> identifier variadic_needs_clause --> variadic_needs ¤ need_clauseA variadic routine is one with a variadic clause (see Why variadic procedures.) The variadic clause in conjunction with the optional variadic_needs clause specifies a template, called a variadic record. A variadic routine invocation can pass zero, one, or more variadic records as arguments. The identifier immediately following the variadic keyword is called the variadic size variable; it has a type of unsigned and is assigned the number of variadic records passed into the variadic procedure. Following the variadic size variable is an optional parameter list enclosed in square brackets ("[...]".) Variadic parameter lists are discussed shortly. The lines following the variadic keyword define the fields and types that make up the variadic record in exactly the same format as a record type declaration.
A variadic procedure with T arguments in the takes clause and V arguments in the variadic clause must be invoked with T + nV arguments, for some non-negative value of n. n is the number of variadic records and is assigned the to the variadic size variable. The types of the first T arguments must match the corresponding types of the takes clause. The remaining nV arguments must match the corresponding types in the variadic clause in a round-robin fashion.
For example, the following two variadic procedures:
procedure sequence takes heap variadic size value unsigned returns vector[integer] ... procedure wire takes heap variadic count x integer y integer returns wire ...can be invoked as follows:
primes := sequence(heap1, 1, 2, 3, 5, 7, 11, 13) # size = 7 fibonacci := sequence(heap1, 1, 1, 2, 3, 5, 8, 13) # size = 7 empty := sequence(heap1) # size = 0 error := sequence(heap1, -1, -2, -3) # Type error, must be unsigned wire1 := wire(heap1, 0, 0, 1, 1) # count = 2 none := wire(heap1) # count = 0 bad := wire(heap1, 1, 2, 3) # Error, no y value for last pairThe values of variadic arguments are accessed using the variadic_with statement (see the variadic_with statement.)
The following example is a simple implemention of the out_stream@print variadic procedure, which requires a variadic_needs clause:
procedure print@out_stream takes output out_stream format_string string variadic count [type] value type returns unsigned variadic_needs procedure format@type takes type, out_stream, in_stream returns unsigned format_stream:: in_stream := format_string~in_stream_convert(heap@standard) index:: unsigned := 0 width:: unsigned := 0 loop for chr:: character := format_stream~characters() as format_chrs if chr = "%" if !format_stream.empty && format_stream~peek() = "%" next chr := format_chrs chr~print(output) width++ else_if index < count variadic_with index++ width += value~format(output, format_stream) else width += output~print(`This routine takes an output stream and a format string followed by a sequence of zero, one, or more arguments of any type. Each argument is put into a variadic record along with an associated routine called format@type. (In addition, the initial object, type@??, is implicitly passed in the variadic record.) Errors are printed by recursively calling itself. The actual implementation of this routine is more sophisticated in that it permits the printing of out-of-order arguments, and fixed width fields.') else chr~print(output) width++ if index < count width += output~print(`<%d arguments not printed>', count - index) return width
If a procedure does not return any values, the returns_nothing clause is specified.
Some procedures, like exit@system, have the attribute that they will never return. (This is different from returning no values.) A procedure that never returns specifies the returns_never keywords for the returns clause. Thus,
procedure exit@system takes return_code integer returns_never ...is the correct definition for the exit@system procedure.
Signals are raised via the signals statement.
{This is a little too terse.}