There are seven coercions in the language, namely
Roughly speaking, the coercions can be arranged in a hierarchy within the hierarchy of contexts thus:
The only coercion not yet met is weakly-dereferencing. However, it is useful to describe all the coercions here. Before we do so, it should be noted that one of the limitations of the language is that you cannot specify the kind of context. Thus if you have a weak context and you would like a firm context, you cannot specify it. However, in any context, you can use a cast (see the section on primaries below) which will always make a context strong and because all coercions are available in a strong context, you can use the cast to specify the mode you require.
This coercion is available in all contexts.
Deproceduring is the process by which a parameterless procedure is
called. For example, the procedure
random, declared in the standard
prelude as having mode PROC REAL
, when
called yields a REAL
. We can represent the coercion
by
PROC REAL
⇒
REAL
The PROC
is “removed”, which is why it is
called deproceduring.
There are occasions when the identifier of a procedure can be written without the procedure being called. In the program fragment
PROC REAL rnd:=random
the right-hand side of the assignment requires the mode PROC
REAL
because the mode of the name identified by
rnd
is REF
PROC
REAL
. Clearly, random
is not called
here.
The only possible ambiguities with deproceduring are those of
assignments and casts. For example, having declared rnd
above, the subsequent assignment
rnd:=random;
yields a value of mode REF PROC REAL
, because the
value of an assignment is the value of the left-hand side (see section
10.8). However, the following
“go-on symbol” indicates that the assignment should now be
voided. It is a rule of the language that voiding takes place before
deproceduring if the unit being voided is an assignment. If, however,
rnd
had been used on its own, as in
rnd;
then it would have been dereferenced, then deprocedured and the
resulting REAL
value voided. This would ensure that any
side-effects (see sections 6.1.6
and 6.2.3) would take effect.
Similarly, in the unit
PROC REAL(rnd);
rnd
(with mode REF PROC REAL
) will be dereferenced, but
the resulting value of mode PROC REAL
will be voided
immediately since it is clear that a REAL
value is not
required. Note that all the code examples using a go-on symbol could
have been written with END
or FI
etc, provided that the
resulting context would have resulted in voiding.
When writing a program, it is common to make mistakes11.1, and one mistake is to write the identifier of a procedure without its parameters (the primary of a call). This is not, strictly speaking, an error. At least, not a grammatical error. However, in such a case, the a68toc compiler will issue a warning:
Proc with parameters voided, parameters of call forgotten perhaps
in which case the mistake should be obvious. Suppose you write the identifier of a procedure in a formula without its parameters, as in
PROC p1 = (INT n)INT: n**2+3; INT a:=4; a:=4+p1;
then the a68toc compiler will issue the message
op + not declared for INT and PROC (INT)INT
The error message for a procedure identifier on the right-hand side of an assignment is
PROC (INT)INT cannot be coerced to INT
Deproceduring only occurs with parameterless procedures.
This is the process of moving from a name to the value to which it
refers (which could also be a name--see chapter 11). For example,
if x
has mode REF REAL
, then in the
formula
x * 3.5
the name x
will be dereferenced to yield a new instance of the
REAL
referred to by x
. The coercion can be
represented by
REF REAL
⇒
REAL
If rx
has mode REF REF REAL
(that is,
rx
can refer to a name of mode REF REAL
),
then the formula
rx * 3.5
will result in rx
being dereferenced twice. In this
case, the coercion could be represented as
REF REF REAL
⇒
REAL
Dereferencing is available in all contexts except soft.
When a name, such as rx
, is dereferenced twice, new
instances of both the values referred to (in the case of
rx
, the REF REAL
and the REAL
values) are created. However, the new instance of the REF
REAL
value is discarded after the creation of the
REAL
value. This has no effect on the elaboration of the
program.
This is a variant of the dereferencing
coercion in which any number of REF
s can be removed except the
last. Thus, in the case of rx
above, weakly-dereferencing would
yield a mode of REF REAL
and could be represented by
REF REF REAL
⇒
REF REAL
This coercion is only available in weak
contexts. It is particularly useful in the
selection of secondaries of structure modes which
contain fields whose mode starts with REF
(see
section 10.6 and
chapter 11).
In this coercion, the mode of a value becomes a
united-mode. For example, if OO
is an operator both of
whose operands are UNION(INT,REAL)
, then in the
formula
3.0 OO -2
both operands will be united to UNION(INT,REAL)
before the
operator is elaborated. These coercions can be represented by
|
⇒ |
|
Uniting is available in firm and strong contexts and must precede rowing.
In a strong context, an integer can be replaced by a real number and a real number replaced by a complex number, depending on the mode required. This can be represented by
INT | ⇒ | REAL |
REAL | ⇒ | COMPL |
If, in a strong context, a multiple is required and a value is provided whose mode is the base mode of the multiple, then the value will be rowed to provide the required multiple. There are two cases to consider:
[]base-mode
. For example, if the required mode is
[]INT
, then the base-mode is INT
. In the identity
declaration
[]INT i = 3the value yielded by the right-hand side (an integer) will be rowed and the coercion can be expressed as
INT
⇒
[]INT
If the value given is a row mode, such as []INT
, then
there are two possible rowings that can occur.
[,]INT a = i
where i
was declared above with mode
[]INT
, the coercion can be expressed as
[]INT
⇒
[,]INT
In this case, an extra dimension is added to the multiple.
[][]INT
as in
[][]INT r = i
then the value on the right-hand side is rowed to yield a
one-dimensional multiple whose base-mode is []INT
. This
coercion can be represented as
[]INT
 
⇒
[][]INT
REF INT
, then a name with mode
REF[]INT
will be created. In this identity
declaration
REF[]INT ni = LOC INTthe local generator yields a name with mode
REF INT
and the rowing coercion yields a name with mode
REF[]INT
and bounds [1:1]
. The coercion can be
represented by
REF INT
⇒
REF[]INT
[]REF INT rri = LOC INTproduces the coercion represented by
REF INT
⇒
[]REF INT
REF[]INT
can be rowed to a name with
mode REF[,]INT
or a non-name with mode []REF[]INT
,
depending on the mode required. Although INT
has been taken as
an example, any mode could have been used.
In a strong context, a value
can be thrown away, either because the mode
VOID is explicitly stated, as in a
procedure yielding VOID
, or because the context demands
it, as in the case of a semicolon (the go-on
symbol). In this case, there are two exceptions to the rule that the
value yielded depends only on the context. Casts and assignments are
voided after the elaboration of the unit, but all other units are
subjected to the usual coercions in a strong context. The following
program illustrates this:
PROGRAM tproc CONTEXT VOID USE standard BEGIN PROC INT p; PROC pp = INT: ( INT i=random int(6); print(i); i ); p:=pp; print((" p:=pp",newline)); pp; print((" pp",newline)); p; print((" p",newline)); PROC INT(p); print((" PROC INT(p)",newline)) END FINISH
The output is
p:=pp +6 pp +1 p PROC INT(p)
In the assignment p:=pp
, the mode required on the
right-hand side is PROC INT
so pp
is not
deprocedured, and p
is neither
dereferenced nor deprocedured after the
assignment has been elaborated. The cast PROC INT(p)
is
elaborated (that is, p
is dereferenced) and then voided
without the procedure p
(or pp
) being
called.
In any context, you have a unit which has, or yields, a value of some mode; and in that context you have a mode which you need. If the value of the mode you have can be coerced to a value of the mode you need (assuming that the two modes differ), then the coercion is legal.
For example, suppose you have a value of mode PROC
REF
INT
in a strong context and the mode you
want is []COMPL
. The required mode can be got via
REF INT
INT
REAL
COMPL
[]COMPL
In practice, coercions are not usually as complicated as this.
Notice that deproceduring can take place before or after
dereferencing, that widening must occur before rowing and that voiding
can only take place after all other coercions. For example, you cannot
coerce []INT
to []REAL
.
REF REF BOOL
⇒
REF BOOL
PROC INT
⇒
UNION(REAL,COMPL)
REF PROC CHAR
⇒
CHAR
PROC REF REAL
⇒
[]REAL
PROC REF BOOL
⇒
BOOL
PROC INT
⇒
UNION([]INT,[]REAL)