A procedure is either NIL
or a triple consisting of:
A procedure that returns a result is called a function procedure; a procedure that does not return a result is called a proper procedure. A top-level procedure is a procedure declared in the outermost scope of a module. Any other procedure is a local procedure. A local procedure can be passed as a parameter but not assigned, since in a stack implementation a local procedure becomes invalid when the frame for the procedure containing it is popped.
A procedure constant is an identifier declared as a procedure. (As opposed to a procedure variable, which is a variable declared with a procedure type.)
A procedure type declaration has the form:
TYPE T = PROCEDURE sigwhere
sig
is a signature specification, which has the form:
(formal_1; ...; formal_n): R RAISES Swhere
formal_
is a formal parameter declaration, as described
below.
R
is the result type, which can be any type but an open array
type. The ``: R
'' can be omitted, making the signature that of a
proper procedure.
S
is the raises set, which is either an explicit set of
exceptions with the syntax {E_1, ..., E_n}
, or the symbol ANY
representing the set of all exceptions. If ``RAISES S
'' is omitted,
``RAISES {}
'' is assumed.
A formal parameter declaration has the form
Mode Name: Type := Defaultwhere
Mode
is a parameter mode, which can be VALUE
, VAR
,
or READONLY
. If Mode
is omitted, it defaults to VALUE
.
Name
is an identifier that names the parameter. The parameter
names must be distinct.
Type
is the type of the parameter.
Default
is a constant expression, the default value for the
parameter. If Mode
is VAR
, ``:= Default
'' must be
omitted, otherwise either ``:= Default
'' or ``: Type
'' can be
omitted, but not both. If Type
is omitted, it is taken to be the
type of Default
. If both are present, the value of Default
must be a member of Type
.
When a series of parameters share the same mode, type, and default,
Name
can be a list of identifiers separated by commas. Such a list is
shorthand for a list in which the mode, type, and default are repeated for
each identifier. That is:
Mode v_1, ..., v_n: Type := Defaultis shorthand for:
Mode v_1: Type := Default; ...; Mode v_n: Type := DefaultThis shorthand is eliminated from the expanded definition of the type. The default values are included.
A procedure value P
is a member of the type T
if it is
NIL
or its signature is covered by the signature of T
,
where signature_1
covers signature_2
if:
signature_1
contains the raises set of
signature_2
.
The parameter names and defaults affect the type of a procedure, but not its value. For example, consider the declarations:
PROCEDURE P(txt: TEXT := "P") = BEGIN Wr.PutText(Stdio.stdout, txt) END P; VAR q: PROCEDURE(txt: TEXT := "Q") := P;Now
P = q
is TRUE
, yet P()
prints ``P
'' and
q()
prints ``Q
''. The interpretation of defaulted parameters is
determined by a procedure's type, not its value; the assignment q := P
changes q
's value, not its type.
Examples of procedure types:
TYPE Integrand = PROCEDURE (x: REAL): REAL; Integrator = PROCEDURE(f: Integrand; lo, hi: REAL): REAL; TokenIterator = PROCEDURE(VAR t: Token) RAISES {TokenError}; RenderProc = PROCEDURE( scene: REFANY; READONLY t: Transform := Identity)
In a procedure type, RAISES
binds to the closest preceding
PROCEDURE
. That is, the parentheses are required in:
TYPE T = PROCEDURE (): (PROCEDURE ()) RAISES {}
m3-support@elego.de