Methods categories
Methods and Types
Types
Polymorphism

Types

CLAIRE uses an extended type system that is built on top of the set of classes. Like a class, a type denotes a set of objects, but it can be much more precise than a class. Since methods are attached to types (by their signature), this allows attaching methods to complex sets of objects.

Definition : A (data) type is an expression that represents a set of objects. Types offer a finer-granularity partition of the object world than classes. They are used to describe objects (range of slots), variables and methods (through their signatures). An object that belongs to a type will always belong to the set represented by the type.

Any class (even parameterized) is a type. A parameterized class type is obtained by filtering a subset of the class parameters with other types to which the parameters must belong. For instance, we saw previously that complex[im:{0.0}] is a parametrized type that represent the real number subset of the complex number class. This also applies to typed lists or sets which use the of parameter. For instance, list[of:{integer}] is the set of list whose of parameter is precisely integer. Since these are common patterns, CLAIRE offers two shortcuts for parameterized type expressions. First, it accepts the expression C[p = v] as a shortcut for C[p:{v}]. Second, it accepts the expression C<X> as a shortcut for C[of = X]. This applies to any class with a type-valued parameter named of; Thus, stack<integer> is the set of stacks whose parameter "of" is exactly integer, whereas stack[of:subtype[integer]] is the set of stacks whose parameter (a type) is a subset of integer.

Finite constant sets of objects can also be used as types. For example, {john, jack, mary} and {1,4,9} are types. Intervals can be used as types; the only kind of intervals supported by CLAIRE 3.0 is integer intervals. Types may also formed using the two intersection (^) and union (U) operations. For example, integer U float denotes the set of numbers and (1 .. 100) ^ (-2 .. 5) denotes the intersection of both integer intervals, i.e. (1 .. 5).

Subtypes are also as type expressions. First, because types are also objects, CLAIRE introduces subtype[t] to represent the set of all type expressions that are included in t. This type can be intersected with any other type, but there are two cases which are more useful than other, namely subtypes of the list and set classes. Thus, CLAIRE uses set[t] as a shortcut for set ^ subtype[t] and list[t] as a shortcut for list ^ subtype[t]. Because of the semantics of lists, one may see that list[t] is the union of two kinds of lists :

Therefore, there is a clear difference between Obviously, we have list<t> <= list[t]. When should you use one or the other form of typed lists or sets ?
  1. use list[t] to type lists that will only be used by accessing their content. A method that uses l:list[t] in its signature will be polymorphic, but updates on l will rely on dynamic (run-time) typing.
  2. use list<t> to type lists that need to be updated. A method that uses l:list<t> in its signature will be monomorphic (i.e., will not work for l:list<t'> with t' <= t), but updates will be statically type-checked (at compile time).
Last, CLAIRE uses tuple and array types. The array type t[] represents arrays whose member type is t (i.e., all members of the array belong to t). Tuples are used to represent type of tuples in a very simple manner: tuple(t1,t2,...,tn) represents the set of tuples tuple(v1,v2, ... ,vn) such that vi belong to ti for all i in (1 .. n). For instance, tuple(integer, char) denotes the set of pair tuples with an integer as first element and a character as second. Also you will notice that tuple(class,any,type) belongs to itself, since class is a class and type is a type.

Classes are sorted with the inheritance order. This order can be extended to types with the same intuitive meaning that a type t1 is a subtype of a type t2 if the set represented by t1 is a subset of that represented by t2. The relation "t1 is a subtype of a type t2" is noted t1 <= t2. This order supports the introduction of the " subtype " constructor: subtype[t] is the type of all types that are less than t.


categories Typesnormal dispatch operationKernel method

%(x:any, y:any) -> boolean

(x % y) returns (x E y) for any entity x and any abstract set y. An abstract set is an object that represents a set, which is a type or a list.


categories Typesnormal dispatch operationKernel method

..(x:integer, y:integer) -> Interval

x .. y returns the interval interval (x .. y).


categories Typesnormal dispatch operationKernel method

<=(x:type, y:type) -> boolean

The order on types is the inclusion: (x <= y) returns true if all members of type x are members of type y.


categories Typesnormal dispatch operationCore method

=type?(self:type, ens:type) -> boolean

returns true if x and y denote the same type. For example =type?(boolean, {true, false}) returns true because defined(boolean) was declared after the two instances true and false were created, so the system knows that no other instances of boolean may ever be created in the future. This equality is stronger than set equality in the sense that the system answers true if it knows that the answer will hold everafter.


categories Typesnormal dispatch Kernel method

final(c:class) -> void

final(c) forbids the user to create any subclass of the class c. If c is a constant class, this is taken as a "diet" compiling directive.


categories Typesnormal dispatch Core method

finite?(self:type) -> boolean

finite?(self) returns true if the type self represents a finite set. Set iteration (with the for loop) can only be done over finite sets.


categories Typesnormal dispatch operationCore method

inherit?(self:class, ens:class) -> boolean

inherit?(self, ens) returns (self % ancestors(ens)).


categories Typesnormal dispatch Core method

member(x:type) -> type

member(x) returns the type of all instances of type x, assuming that x is a CLAIRE type which contains objects y such that other objects z can belong to. If this is the case, member(x) is a valid type for all such z, otherwise the returned value is the empty set. For instance, if x is list[integer], all instances of x are lists that contain integers, and all members of these lists are integers. Therefore, member(list[integer]) is integer.