45 Types
Up to now we have used the word ‘type’ informally to refer to the kinds of values introduced by nominal type declarations. We now give the semantic definition of a type and explain how types relate.
A type is a semantic classification of values. Each type has a carrier set: the set of values classified by that type. Predica types are introduced or described in the following ways:
- It is a predefined type.
- It is a structural type.
- It is a nominal type introduced by a nominal type declaration.
- It is a type expression formed from existing types, such as
Set<T>, asubtype T where prefinement, a union, or an intersection. - It is the intersection of two or more comparable types, where comparability ensures a unique least common supertype with defined equality
Any type may have multiple names.
In the semantic model, type equality is equality of carrier sets. Consequently, two types are equal exactly when they have the same carrier set.
A type expression denotes a type, and therefore determines a carrier set drawn from a fixed background universe of sets. Type expressions provide the syntax for referring to types.
Some declarations, such as value and entity, introduce new nominal type identity. Other
declarations, such as type aliases, bind a name to a type expression without creating a new carrier
set. A subtype T where p type expression denotes a subset of an existing type.
Type test expressions
The expression L isa T tests the relationship of its left operand L to the type denoted
by its right operand T. Its result type is Boolean. The left operand may be either a value
expression or a type expression.
When L is a value expression, L isa T tests whether the value denoted by L is a member
of T. The test is about the value of L, not the syntactic form of the expression that
produced it. When L is a type expression, L isa T tests whether the type denoted by L
is a subtype of T.
abstract entity Animal {}
entity Dog isa Animal
{
String bark;
}
entity Owner
{
Animal pet;
→ Boolean petIsDog = pet isa Dog;
→ String sound? = if pet isa Dog then pet.bark else none;
}
For a value left operand, a type test is invalid when the static type known for the value is
necessarily disjoint from T, because such a test cannot be satisfied. For a type left operand,
the test is false when the left type is not a subtype of T.
A positive type test narrows the static type known for the tested expression in the guarded
scope. For example, in if pet isa Dog then pet.bark else none, the then-branch may use
members of Dog through pet. In pet isa Dog ∧ pet.bark = "woof", the right-hand side of
the conjunction is checked with the same positive narrowing. The test does not introduce a
general negative narrowing rule for else-branches or disjunctions.