CSE 341 - Types

Traditional definition of "type": a type is a set of values and operations on those values. This works fine for polymorphic types as well as monomorphic ones, and for subtypes. In object-oriented languages it is useful to distinguish abstract types (defined by message protocols) and concrete types.

Some Definitions

Type error
A type error occurs if a function or procedure expects an argument of type s but is applied to an argument of something that does not have type s.
Type safe
A program is type safe if we can guarantee that it will execute without type errors. A language is type safe if it guarantees that all type errors will be detected, either at compile time (static type checking), run time (dynamic type checking), or a mixture of both. Scheme, Smalltalk, Java, Miranda, and CLP(R) are examples of type safe languages. Fortran, C, and C++ are examples of languages that aren't type safe.
Strongly typed
The book's definition is that a type system is strong if it accepts only type safe expressions. (Note that it doesn't have to accept every type safe expression.) Another meaning that you may encounter is that strongly typed also implies statically typed.
Weakly typed
Weakly typed means "not type safe". Fortran and C are examples of weakly typed languages.

overloading and polymorphism ... see Miranda notes

Type Equivalence

In an imperative, non-object oriented language such as C, Pascal, Modula-2, or Ada, when are two types equal? The two usual choices are name equivalence and structural equivalence. A modified form of name equivalence is the standard choice. Here are some examples to consider (in Ada):

A : array(1 .. 10) of BOOLEAN;
B : array(1 .. 10) of BOOLEAN;

C, D : array(1 .. 10) of BOOLEAN;
Ada defines A and B as of different types, but C and D are both of the same type. Here's another example, with some type declarations:

type VEC is array(1 .. 10) of INTEGER;

type VEC2 is array(1 .. 10) of INTEGER;

A : VEC;
B, C : VEC;
D : VEC2;

type PERSON is 
  record 
    NAME : STRING(1 .. 120);
    POUNDS : INTEGER; 
  end record;

type ENGLISH_ACCOUNT_PAYABLE is 
  record 
    NAME : STRING(1 .. 120);
    POUNDS : INTEGER; 
  end record;


subtype SMALL_INT is INTEGER range -10 .. 10;

I : INTEGER;
J : SMALL_INT;
Here A, B, and C are all of the same type; D is of a different type. PERSON and ENGLISH_ACCOUNT_PAYABLE are different types. This is all consistent with pure name equivalence. I and J are both integers. (In pure name equivalence they would be different -- this is the "modified" part.)

The structural equvalence rule in its pure form would say that A, B, C, and D are all of the same type, and PERSON and ENGLISH_ACCOUNT_PAYABLE are the same type. Algol-68 is an example of a language that uses structural equivalence. This kind of structural equivalence has pretty much fallen out of favor though.

C would say that A, B, C, and D are all of the same type, and PERSON and ENGLISH_ACCOUNT_PAYABLE are different types. C uses structural equivalence, except for records (structs).

Other Type Topics

Are the bounds part of an array type? Pascal originally said yes; it is generally agreed now that they shouldn't be.

Variant records -- are they done in a type safe way? Pascal: no. Ada: yes. In Ada, a variant record must have a discriminant that lets the compiler distinguish between the cases; the discriminant must be set at the same time as the variant fields.

type DEVICE is (PRINTER, FLOPPY, HARD_DISK);
type STATE is (UP, DOWN);

type PERIPHERAL(UNIT : DEVICE := PRINTER) is
  record
    STATUS: STATE;
    case UNIT is
      when PRINTER => PAGE_LENGTH : FLOAT;
      when others => MEGABYTES : INTEGER;
    end case;
  end record;

P : PERIPHERAL;

P := (UNIT => FLOPPY, MEGABYTES => 2);
-- not allowed: P.unit := printer;