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

4.3 Matching Against Type Patterns

4.3.4 Static vs. Dynamic Matching

At run-time, the dynamic type of the actual argument is used to compute the instantiation of any implicitly-bound type parameters. During static type checking, however, the type checker does not know the dynamic type of its arguments. Fortunately, the static type checker can perform a similar matching process using the static types of the arguments to the call to verify type-correctness of the call and to compute the static type of the result. The static checker uses type variables to stand for the dynamic types of the arguments to the call, and these type variables are statically known to be subtypes of the static type of the arguments. If the matching process succeeds using these static type variables, then the match is guaranteed to succeed at run-time.

Usually, the distinction between the dynamic and the static type is unimportant. For example, with the simple min method defined above, the caller will know that the type of the result is a subtype of the least-upper-bound of the dynamic types of the two arguments. Given the static knowledge that both arguments are of some dynamic type that is a subtype of a particular static type, the caller can infer the static knowledge that the result is some subtype of that static type. Static type information already implies only that the dynamic type of some expression is some subtype of the static type, so calculating static approximations to implicitly-bound type variables is what the type checker has been doing all along.

In two circumstances, however, the distinction between instantiating a type parameter with a dynamic type versus a static type is important. If a implicitly-bound type parameter is used as a normal type for another declaration, i.e., as an upper bound type, then legal actual parameters must be known to be equal to or subtypes of the implicitly bound type variable. For example, if min were rewritten as follows:

method min(x1:'T <= comparable, x2:T):T {
	if (x1 < x2, { x1 }, { x2 })}
the second argument would be required to be a subtype of the dynamic type of the first argument. This requirement could be quite difficult to guarantee statically and is probably not what the programmer meant. Type parameters are usually used directly as type declarations when they are bound to the instantiating parameter of a parameterized type, as in the following method:

method store(a:array['T], index:int, value:T):void {
	-- store value as the indexth element of the array a
}
Here, T will be bound to the type of the elements of the array, specified when the array was created, and usually the value argument will be known to be a subtype of that type at the call site, perhaps because it had just been extracted from an array of similar type.

The distinction between dynamic types and static types for instantiation also appears when instantiating a parameterized object. For example, one way to write the new_array method might be the following:

method new_array(size:int, initial_value:'T):array[T] {
	concrete object isa array[T] {
		size := size, initial_value := initial_value } }
Given an initial value of dynamic type T, an array is returned with the type T as the instantiating value. Because of the fetch and store operations defined on arrays, this array will only be able to contain elements that are subtypes of the dynamic type of its initial value. Usually, this would be too restrictive. To correct this problem, the real method to create a new array is explicitly parameterized with the desired type of the elements:

method new_array[T](size:int, initial_value:T):array[T] {
	concrete object isa array[T] {
		size := size, initial_value := initial_value } }
Instantiations of parameterized objects record their instantiating types as part of their dynamic run-time state. The instantiating types are used to determine the subtyping relation of the object and when matching the parameterized object's type against a type pattern of the form type[...,'Ti <= typei,...].


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

Generated with Harlequin WebMaker