Subsections

- Exercises

# Balancing

In section 6.1, it was pointed out that the context of a routine denotation is passed on to the last unit in the denotation. In the example given, the body of the routine denotation was a closed clause. The yield of the routine was a value of mode `INT`, but the yield of the last unit was a name with mode `REF INT`. Since the context of the body of a routine denotation is strong, the name is dereferenced to get an `INT`. This principle is applicable to all enclosed clauses.

Now conditional clauses, case clauses and conformity clauses can yield one of a number of units, and so it is quite possible for the units to yield different values of different modes. The principle of balancing allows the context of all these units, except one, to be promoted to strong whatever the context of the enclosed clause. Balancing is also invoked for identity relations which are dealt with in the next chapter.

Considering, for example, the formula

       x * (a > 0|3.0|2)

the context of the conditional clause is firm which means that widening is not allowed. Without balancing, the conditional clause could yield a `REAL` or an `INT`. In this example, the principle of balancing would promote the context of the `INT` to strong and widen it to `REAL`. Balancing thus means “making the modes the same”.

In a balanced clause, one of the yielded units is in the context of the whole clause and all the others are in a strong context, irrespective of the actual context of the clause. Here is an example of a balanced case clause

       INT i:=3,j:=4,a:=2;
       PROC ij = REF INT: (random < 0.5|i|j);
       print(2 + (a|i,ij|random))

where the `a` yields an `INT` in a meek context (that of the enquiry clause). In this example, the modes of the values that can be yielded by the case clause are `REF INT` (`i`), `PROC REF INT` (`ij`) and `PROC REAL` (`random`). In a firm context, the modes become `INT`, `INT` and `REAL`. Thus the context of `random` is taken to be firm, and the context of `i` and `ij` is promoted to strong and they are both dereferenced and widened to `REAL`. The result is that the case clause will yield a `REAL` value even though the clause as a whole is in a firm context (it is an operand of the operator `+`).

If instead, we had

       PROC REAL r:=random;
       (a|i,ij|j):=ENTIER r

using the declaration of `ij` in the previous example, then balancing would not be needed to produce the required mode. The modes of the yielded units are `REF INT`, `PROC` `REF` `INT` and `REF INT` respectively. In a soft context, these modes would yield `REF INT` (no dereferencing allowed), `REF INT` (deproceduring is allowed) and `REF INT`. Thus the case clause would yield `REF INT` on the left-hand side of the assignment.

Here is an example of a conditional clause which cannot be balanced:

       INT i:=2, REAL a:=3.0;
       (random > 0.5|i|r):=random

In this case, the two parts of the conditional clause yield `REF INT` and `REF REAL`. There is no coercion which will convert a `REF INT` into a `REF REAL`. When you try to compile this, the a68toc compiler gives the following error message:

       lhs of assignment must be a reference

The balancing means that one of the yields is in a strong context and so is dereferenced which yields a value which is not a name.

The method of determining whether balancing is possible is as follows:

1. Determine the context of the choice clause.
2. In the context found in step 1, determine the mode yielded by each unit in the choice clause.
3. If there is a mode such that all the modes but that one can be strongly coerced to that mode, the clause can be balanced.

## Exercises

10.12
  In each of the following clauses, state whether balancing is possible, and if so, the mode yielded by the balanced clause. These declarations are in force:

         INT i,j, REAL a,b:=random;
         PROC ij = REF INT: (b>0.5|i|j);
         PROC r = REAL: random * random;
         UNION(INT,REAL) ri:=(random>0.6|i|b)

  Ans
  (a)
    `a:=2.0*(random<0.3|i|b)`

  (b)
    `(j<2|ij|b):=r`

  (c)
    `a:=((ri|(INT r):r,(REAL r):r)<1|2|3)`

  (d)
    `b:=2.0*(j>3|4|SKIP)`