parameterization ==>
{ parameter_declaration { , parameter_declaration } } |
parameter_declaration ==>
uppercase_identifier [ < type_specifier ] |
Class definitions may optionally have one or more parameters within enclosing braces. Parameters are placeholders for actual types that are filled in at a point of use. Whenever a parameterized class is referred to, its formal parameters are instantiated with type specifiers. Parameter names are local to the class definition in which they appear and they shadow non-parameterized types with the same name. Parameter names must be all uppercase, and they may be used within the class definition as type specifiers. Partial classes may not be used as parameters. There is no implicit type relationship between different parameterizations of a class.
If a parameter declaration is followed by a type constraint clause ('<' followed by a type specifier), then the parameter may only be replaced by subtypes of the constraining type. If a type constraint is not explicitly specified, then '< $OB' is taken as the constraint. A type constraint clause may not refer to 'SAME'. A class definition must satisfy all typing rules when its parameters are replaced by any potential subtype of their constraining type. This allows type-safe independent compilation: classes may be checked once for all parameterizations by type checking using prototypical unique subtypes of the type constraints.
An instantiated parameterized class definition is very similar to a non-parameterized copy of the original definition in which each formal parameter occurrence is replaced by the specified actual type. Parameterization may be thought of as a structured macro facility; however, it is not the same as simple textual replacement, because the resolution of overloading uses type constraints instead of actual parameter types (See Sather supports routine and iterator overloading. In addition to the name, the number, types, and modes of arguments in a call and whether a return value is used all contribute to the selection of the method. The modal_list portion of a call must supply an expression corresponding to each declared argument of the method. There must exist a method with the specified name such that:). Note: at this time the ICSI compiler efficiently but incorrectly resolves overloading based on fully instantiated types rather than type constraints.
NOTE: The rule for resolving overloading in parametrized classes based on the type-bounds rather than the instantiated type is necessaryto permit separate compilation of parametrized classes. If the type of the parameter is used when permitting overloading, two kinds of problems can arise. First of all, there is a type-checking problem. It is not possible to determine whether or not signatures conflict for all instantiations of the parametrized class. For instance, in the class BAR{T } the signatures '[1] foo(a:T) and [2] foo(a:$STR)' will only conflict when T is abstract and not a subtype of $STR. The second problem is that method selection might require mulitple dispatch. In the example mentioned, if the call has the signature foo(INT), this will match signature [1] in BAR{INT}. However in BAR{MATRIX}, the same call foo(INT) will match [2]. This behavior would make it impossible to separately compile parametrize classes without multiple dispatch, which may considerably reduce the efficiency of the resulting implementation..
Example 3-10. Most Sather code resides in ordinary reference classes. A frequently used class from the standard library is 'ARRAY{T}', which is a conventional array of the parameterized type 'T'. Here we show the method 'contains', which uses 'T'. For example, an 'ARRAY{INT}' would support the call 'contains(5)'.
class ARRAY{T} is ... contains(e:T):BOOL is ... end; ... end; |
Example 3-11. The priority queue abstraction requires parameter type constraints. Elements need to be comparable to each other, no matter what the parameter instantiation is. This is specified by the parameter type constraint '< $IS_LT{T}', which itself uses the parameter 'T'.
abstract class $PQ{T < $IS_LT{T}} < ... is top: T; pop: T; insert(e: T); clear; is_empty: BOOL; end; |