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')`type'.GotOper.
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;