previous next top complete contents complete index framed top this page unframed
A $PROCVAR is implemented as two components: a POINTER to a data section and a component that represents the PROCEDURE to be called in the control section corresponding to the data section. The exact layout of the components of a $PROCVAR is not documented because it is subject to change in future releases of MAINSAIL.
8.1. Declaration
A $PROCVAR p is declared as follows:
$PROCVAR(modelProc) p;
where modelProc (p's model PROCEDURE) is one of the following:
The PROCEDUREs that p can reference have the same result and parameters as modelProc. If no appropriate declaration is available for modelProc, a FORWARD declaration may be provided just to serve as a model PROCEDURE (note that a body need not be provided for a FORWARD PROCEDURE if it is not called). For convenience, the macro $MODEL is defined as a synonym for FORWARD; it clarifies to the human reader that a PROCEDURE declaration will be used just as a model PROCEDURE.
The form $PROCVAR() p or $PROCVAR p declares an unmodeled $PROCVAR in which the characteristics of the PROCEDUREs that p can reference are not constrained; otherwise a $PROCVAR is modeled. p:modelProc (where modelProc is as described above) may be used to indicate explicitly the model PROCEDURE for an unmodeled $PROCVAR p. An unmodeled $PROCVAR p can be used in a call only in the form p:modelProc, since otherwise the compiler does not know the characteristics of the result and parameters. Unmodeled $PROCVARs should seldom be needed. p:modelProc is unsafe since the compiler does not currently check that the characteristics of p are really as described by modelProc (except on a SUPERCHECK platform; see Chapter 18).
Examples of $PROCVAR declarations:
$MODEL INTEGER PROCEDURE foo (REAL x);
$PROCVAR(foo) ARRAY(0 TO 10) ary;
$PROCVAR(foo) PROCEDURE (INTEGER i) proc;
Any variable, field, ARRAY, or PROCEDURE can be of type $PROCVAR.
A $PROCVAR can be a parameter. An OPTIONAL $PROCVAR parameter cannot be declared with an explicit default; i.e., OPTIONAL(v) is not allowed.
INIT is not allowed for a dynamic ARRAY of $PROCVARs.
8.2. Zero
$NULLPROCVAR is the Zero $PROCVAR; its components are Zero.
All $PROCVARs (even local variables)
are initialized to $NULLPROCVAR.
8.3. Assignment Compatibility
Two $PROCVARs
pv1 and pv2 are assignment compatible, and the assignment:
pv1 := pv2
is legal, if either pv1 or pv2 is unmodeled or if they are both modeled and the model PROCEDUREs are compatible, which requires that all the following conditions be satisfied:
A $PROCVAR pv2 passed to a MODIFIES $PROCVAR pv1 must be assignment compatible for both pv1 := pv2 and pv2 := pv1.
A $PROCVAR that has somehow been initialized so it does not reference a PROCEDURE compatible with its declaration results in undefined behavior when it is invoked.
The notion of safe assignments involving $PROCVARs is used in
determining the legality and the type of the result of an IF
expression whose result expressions are $PROCVARs, as discussed
in Section 4.5.
the rules above imply the legality and safety of assignments as
shown below:
A $PROCVAR can be assigned
or passed only to an assignment-compatible
$PROCVAR.
A $PROCVAR p is used to invoke the
PROCEDURE it references by following
it with a (possibly empty) argument list: p(...).
The argument parentheses
are required even if there are no arguments; in the absence of argument
parentheses, a $PROCVAR is treated as a variable rather than an
invocation. An attempt to use a Zero $PROCVAR in a call results in a
NULLPOINTER access if checking is in effect;
otherwise, the effect is undefined.
If p is a $PROCVAR:
8.3.1. Safe and Unsafe Assignment of $PROCVARs
Assignments involving
$PROCVARs can either be safe or unsafe,
similar to the way that assignments involving
POINTERs, ADDRESSes,
or ARRAYs can be safe or unsafe. A legal assignment of
$PROCVAR
pv2 to $PROCVAR pv1
is safe if any of the following conditions is
satisfied:
8.3.2. Examples of Safe and Legal $PROCVAR Assignments
Given the following declarations:
CLASS c (INTEGER i);
CLASS(c) d (STRING s);
$MODEL POINTER(c) PROCEDURE returnC;
$MODEL POINTER(d) PROCEDURE returnD;
$MODEL POINTER PROCEDURE returnUnclassified;
$MODEL PROCEDURE cParm (POINTER(c) p);
$MODEL PROCEDURE dParm (POINTER(d) p);
$MODEL PROCEDURE uParm (POINTER p);
$MODEL PROCEDURE cProdParm (PRODUCES POINTER(c) p);
$MODEL PROCEDURE dProdParm (PRODUCES POINTER(d) p);
$MODEL PROCEDURE uProdParm (PRODUCES POINTER p);
$MODEL PROCEDURE cRefParm ($REFERENCE $RECORD(c) p);
$MODEL PROCEDURE dRefParm ($REFERENCE $RECORD(d) p);
$MODEL PROCEDURE untypedRefParm ($REFERENCE p);
POINTER(c) pc;
POINTER(d) pd;
POINTER up;
$PROCVAR unm;
$PROCVAR(returnC) prc;
$PROCVAR(returnD) prd;
$PROCVAR(returnUnclassified) pru;
$PROCVAR(cParm) pcp;
$PROCVAR(dParm) pdp;
$PROCVAR(uParm) pup;
$PROCVAR(cProdParm) cpp;
$PROCVAR(dProdParm) dpp;
$PROCVAR(uProdParm) upp;
$PROCVAR(cRefParm) crp;
$PROCVAR(dRefParm) drp;
$PROCVAR(untypedRefParm) urp;
unm := prc; # Legal and safe
prc := unm; # Legal but not safe
# (not caught by STRICTCLASSES)
pc := pd; # Legal
pc := up; # Legal but not safe
# (but not caught by STRICTCLASSES)
pd := pc; # Legal but not safe
# (caught by STRICTCLASSES)
pd := up; # Legal but not safe
# (but not caught by STRICTCLASSES)
up := pc; # Legal
up := pd; # Legal
prc := prd; # Legal; any PROCEDURE that returns a d POINTER
# also returns a c POINTER
prc := pru; # Legal
prd := prc; # ILLEGAL -- returning a c doesn't necessarily
# mean returning a d
prd := pru; # Legal
pru := prc; # Legal but not safe
# (not caught by STRICTCLASSES)
pru := prd; # Legal but not safe
# (not caught by STRICTCLASSES)
pcp := pdp; # ILLEGAL -- you can pass any POINTER to c to pcp,
# but pdp's PROCEDURE would require a pdp POINTER
pcp := pup; # Legal
pdp := pcp; # Legal. You can only pass POINTER(d) to pdp,
# which necessarily means you are passing
# POINTER(c)
pdp := pup; # Legal
pup := pcp; # Legal but not safe
# (not caught by STRICTCLASSES)
pup := pdp; # Legal but not safe
# (not caught by STRICTCLASSES)
cpp := dpp; # Legal. You can pass a POINTER(c) to cpp, and
# any POINTER(d) is also a POINTER(c)
cpp := upp; # Legal but not safe
# (not caught by STRICTCLASSES)
dpp := cpp; # ILLEGAL -- runs risk of assigning a POINTER(c)
# that is not really a POINTER(d) to a POINTER(d)
dpp := upp; # Legal but not safe
# (not caught by STRICTCLASSES)
upp := cpp; # Legal
upp := dpp; # Legal
crp := drp; # ILLEGAL -- not every $RECORD(c) $REFERENCE can be
# a $RECORD(d) $REFERENCE
crp := urp; # Legal
drp := crp; # Legal
drp := urp; # Legal
urp := crp; # Legal but not safe
# (but not caught by STRICTCLASSES)
urp := drp; # Legal but not safe
# (but not caught by STRICTCLASSES)
8.4. Operations
A $PROCVAR can be an operand of
OR, AND, NOT, =, NEQ, and :=.
Two $PROCVARs are considered equal if and only if they represent the
same PROCEDURE in the same data section.
8.5. $PROC
$PROC(localProc)
is a $PROCVAR(localProc) that references the local
PROCEDURE localProc in the current data section.
The compiler ensures that a
body for localProc is compiled into the current
MODULE so that a $PROCVAR
can reference it.
If m is a MODULE with a PROCEDURE field f, $PROC({m.}f) is a $PROCVAR({m.}f) that references the PROCEDURE that would be invoked by {m.}f. m is automatically bound if necessary to obtain a POINTER to the bound data section.
If p is a POINTER(c) and f is a PROCEDURE field of c, $PROC(p.f) is a $PROCVAR(c.f) that references the PROCEDURE that would be invoked by p.f.
A MAINSAIL system PROCEDURE must not be used as an argument
to $PROC, or as a modelProc, since what appears to be a
PROCEDURE might
actually be a variable, macro, or GENERIC PROCEDURE.
Even if a given system identifier
is a PROCEDURE in the current release, XIDAK reserves the
right in future releases to change it to a variable, macro,
or GENERIC PROCEDURE, or to add undocumented
OPTIONAL parameters
(provided that its invocation syntax does not change).
8.6. Initialization
A $PROCVAR pv can be initialized (e.g., by assignment or argument
passing) as illustrated by the following assignments:
pv := $NULLPROCVAR; # pv references no PROCEDURE
pv := x; # x is a $PROCVAR
pv := y(...); # y is a PROCEDURE or $PROCVAR that returns
# a $PROCVAR
pv := $PROC(p); # p is a PROCEDURE, which pv now references
8.7. $newProcvar
$newProcvar is a
PROCEDURE that creates an unmodeled $PROCVAR
given a data section
and a PROCEDURE name.
This PROCEDURE should be used only when
$PROC cannot be used. It is
unsafe since it allows the formation of a $PROCVAR that references a
PROCEDURE of unknown characteristics.
8.8. $PROCVAR Example
Example use of $PROCVARs:
INTEGER PROCEDURE strCompare (STRING s1,s2);
...
PROCEDURE sortStrings (STRING ARRAY(1 TO *) ary;
OPTIONAL $PROCVAR(strCompare)
cmpProc);
BEGIN
INTEGER i,j;
IF NOT cmpProc THEN cmpProc := $PROC(strCompare); # default
. . .
CASE cmpProc(ary[i],ary[j]) OFB
. . .
END;
INTEGER PROCEDURE alternateStrCompare (STRING s1,s2);
...
sortStrings(ary); # Uses strCompare to compare strings
sortStrings(ary,$PROC(alternateStrCompare));
# Uses alternateStrCompare instead
MAINSAIL Language Manual, Chapter 8