Next: , Previous: TypeDenot, Up: TypeProp


7.2 Associating operators with types

It must be possible to carry out operations on values of each user-defined type. Such operations could be defined as procedures. If procedures are the only operators that can be applied to values of the user-defined type, and values of the user-defined type can only be produced by procedures, then no additional type analysis mechanisms are required (see Procedure Definition and Call). Often, however, one needs to define operators or coercions to make the user-defined type viable. Here are two examples:

The type analysis modules require any user-defined operators or coercions to be integrated with those defined by the language (see Language-Defined Operators). This can be done by using the OIL CLASS mechanism (see Class definition).

The OIL CLASS mechanism allows one to specify a set of operators and coercions in essentially the form used for language-defined operators. That specification is associated with a particular type construction mechanism (e.g. subranges), and is instantiated whenever a new type is constructed via that mechanism. The instantiation creates the specific set of operators and coercions associated with the new type.

Here is an OIL Class specifying the conversions needed for a Mystery subrange type. This specification is valid for all subrange types; it is a template for the necessary operators rather than a definition of those for a particular subrange:

     INDICATION castInd: narrow;
     
     CLASS Subrange() BEGIN
       COERCION   widen(Subrange): intType;
       OPER       narrow(intType): Subrange;
     END;

The empty parameter list in Subrange() indicates that the operators and coercions for a particular subrange don't depend on any types peculiar to that subrange (other than the subrange type itself). Within the class body, Subrange stands for the subrange type.

Two operators are used to relate the new subrange type to the language-defined intType. The first converts a value of the subrange type into an integer. It is a coercion, and can be applied by the type analysis in any context where a value of the subrange is given and an integer is required by the context. The second converts an integer to a value of the subrange type. It is one of the operators identified by the castInd indication.

Each OIL class must be instantiated in the lower context of the appropriate type denotation. The Expression module provides three context-dependent instantiation computations for this purpose:

InstClass0(`type',`cls')
InstClass1(`type',`cls',`arg1')
InstClass2(`type',`cls',`arg1',`arg2')
Instantiate an OIL class, establishing the post-condition `type'.GotOper.
In each case, `type' is a grammar symbol playing the TypeDenotation role and `cls' is the definition table key representing the OIL class. For InstClass1 and InstClass2, `argi' is the definition table key representing a class argument. We have never encountered a situation requiring an OIL class with more than two parameters.

The Defer chains of the keys are searched by the instantiation operation, so that keys for either types or type identifiers are satisfactory. Also, these operations verify that the definition table key `type'.Type actually represents a type before instantiating the class. No error is reported if the key does not represent a class, because that situation arises routinely when the language defines a structural equivalence relation among types (see Structural Type Equivalence).

Here is the instantiation of the Subrange class in Mystery:

     RULE: SubrTy ::= '[' Number 'TO' Number ']'
     COMPUTE InstClass0(SubrTy,Subrange);
     END;