[Next] [Previous] [Up] [Top] [Contents] [Index]

4.1 Explicit Parameterization

4.1.5 Type Checking Instantiations

To type-check a message with explicit type parameters, signatures with matching names, number of parameters, and number of arguments are located. For each signature, the actual type parameters are bound to the formal type parameters of the signature, and then the formal argument types of the signature are compared to the actual argument types at the call site. A signature is applicable to the call site if the actual types are subtypes of the corresponding formal argument types, as described in section 3.6.1. Once a signature is deemed applicable, then the actual type parameters are compared against the upper bounds of the formal type parameters; if these actual parameters are not subtypes of the corresponding upper bounds, then an "illegal instantiation" error is reported.

To type-check the implementation of a parameterized signature, all methods with the same name, number of type parameters, and number of arguments as the signature are collected. The same rules on conformance, completeness, and consistency as given in section 3.6.2 are verified, with the modification that, when checking the formal argument types of the method against those in the signature, occurrences of the method's formal type parameters are substituted with the signature's corresponding formal type parameters. In addition, the upper bound of a formal type parameter of the signature must be a subtype of the corresponding upper bound of the method; this is a kind of contravariance requirement for type parameter constraints.

All instantiations of parameterized objects and types are checked that the instantiating types are subtypes of the upper bounds of the corresponding formal type parameters.

It can be tricky to verify that an instantiating type parameter is a subtype of the upper bound of the corresponding formal type parameter, if one formal type parameter is used as the upper bound of another formal type parameter. In this case, the instantiator must be able to show statically that the bounded actual type parameter is indeed a subtype of the bounding actual type parameter. If these actual types are themselves formal type parameters in the caller, then such a relationship may be difficult to show. For example, consider the following four methods:

method base[T1, T2 <= T1](x:T1, y:T2):void { ... }
method client1() { base[num,int](4.5, 3); }
method middle[S1, S2 <= num](a:S1, b:S2):void { base[S1,S2](a, b); }
method client2() { middle[int,num](3, 4.5); }
The base method requires that its second type parameter always be a subtype of its first type parameter. The client1 method satisfies this requirement, assuming that int is a subtype of num. However, the middle method does not meet this requirement: even though the upper bound of S2 (num) is known to be a subtype of the upper bound of S1 (any), a particular instantiation of middle may not preserve such a relationship. The method client2 illustrates such an instantiation. Consequently, the static type checker will flag the invocation of base in middle as type-unsafe.


The Cecil Language: Specification and Rationale, Version 2.1 - 25 MARCH 1997
[Next] [Previous] [Up] [Top] [Contents] [Index]

Generated with Harlequin WebMaker