2 Values and Types

. Types of values.

. Primitive, composite, recursive types.

. Type systems: static vs dynamic typing, type completeness.

. Expressions.

. Implementation notes. © 2004, D.A. Watt, University of Glasgow / C. Huizing TU/e 1

1 Types (1)

. Values are grouped into types according to the operations that may be performed on them. . Different PLs support different types of values (according to their intended application areas): • Ada: booleans, characters, enumerands, integers, real numbers, records, arrays, discriminated records, objects (tagged records), strings, pointers to data, pointers to procedures. • C: enumerands, integers, real numbers, structures, arrays, unions, pointers to variables, pointers to functions. • Java: booleans, integers, real numbers, arrays, objects. • Haskell: booleans, characters, integers, real numbers, , disjoint unions, lists, recursive types. 2

2 Types (2)

. Roughly speaking, a type is a of values: • v is a value of type T if v ∈ T. . E is an expression of type T if E is guaranteed to yield a value of type T. . But only certain sets of values are types: • {false, true} is a type, since the operations not, and, and or operate uniformly over the values false and true. • {…, –2, –1, 0, +1, +2, …} is a type, since operations such as and multiplication operate uniformly over all these values. • {13, true, Monday} is not considered to be a type, since there are no useful operations over this set of values. 3

3 Types (3)

. More precisely, a type is a set of values, equipped with one or more operations that can be applied uniformly to all these values. . The of a type T, written #T, is the number of values of type T.

4

4 Primitive types

. A primitive value is one that cannot be decomposed into simpler values. . A primitive type is one whose values are primitive. . Every PL provides built-in primitive types. Some PLs also allow programs to define new primitive types.

5

5 Built-in primitive types (1)

. Typical built-in primitive types: Boolean = {false, true} PL- or implementation- Character = {…, ‘A’, …, ‘Z’,defined set of characters …, ‘0’, …, ‘9’, (ASCII, ISO-Latin, or …} Unicode) PL- or implementation- Integer = {…, –2, –1, defined set of whole 0, +1, +2, …} numbers PL- or implementation- Float = {…, –1.0, …, defined set of real 0.0, +1.0, …} numbers . Names of types vary from one PL to another: not significant.

6

6 Built-in primitive types (2)

. : #Boolean = 2 #Character = 128 (ASCII), 256 (ISO-Latin), or 32768 (Unicode) #Integer = max integer – min integer + 1 . Note: In some PLs (such as C), booleans and characters are just small integers.

. Infinite cardinalities do exist (Integer in Mathematica, e.g.)

7

7 Defined primitive types

. In Ada we can define new numeric types. . In Ada and C we can define new enumeration types simply by enumerating their values (called enumerands).

Java 1.5 has them also: public enum Jam {apricot, blueberry, codfish }

8

8 Example: Ada numerics

. Type declaration: type Population is range 0 .. 1e10; . Set of values:

Population = {0, 1, …, 1010} . Cardinality:

#Population = 1010+1

9

9 Example: Ada enumerations

. Type declaration: type Color is (red, green, blue); . Set of values: Color = {red, green, blue} . Cardinality: #Color = 3

10

10 Composite types

. A composite value is one that is composed from simpler values. . A composite type is a type whose values are composite. . PLs support a huge variety of composite types. . All these can be understood in terms of a few concepts: • Cartesian products (tuples, structures, records) • mappings (arrays) • disjoint unions (algebraic data types, discriminated records, objects) 11 • recursive types (lists, trees, etc.) ! 11 Cartesian products (1)

. In a , values of several types are grouped into tuples. . Let (x, y) stand for the pair whose first component is x and whose second component is y.

. Let S × T stand for the set of all pairs (x, y) such that x is chosen from set S and y is chosen from set T:

S × T = { (x, y) | x ∈ S; y ∈ T } hence the “×” notation . Cardinality: 12 #(S × T) = #S × #T

12 Cartesian products (2)

. We can generalise from pairs to tuples. Let S1 × S2 × … × Sn stand for the set of all n-tuples such that the ith component is chosen from Si:

S1 × S2 × … × Sn = { (x1, x2, …, xn) | x1 ∈ S1; x2 ∈ S2; …; xn ∈ Sn } . Basic operations on tuples: • construction of a from its component values • selection of an explicitly-designated component of a tuple. so we can select the 1st or 2nd (but not the ith, if i is not fixed) component 13 • Records (Ada), structures (C), and tuples (Haskell) can all be understood in terms of Cartesian products 13 Example: Ada records (1)

. Type declarations: type Month is (jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec); type Day_Number is range 1 .. 31; type Date is record m: Month; d: Day_Number; end record; . Application code: someday: Date := (jan, 1); record … construction put(someday.m+1); put("/"); component put(someday.d); 14 someday.d := 29; someday.m := selectionfeb; 14 Example: Ada records (2)

. Set of values: Date = Month × Day-Number = {jan, feb, …, dec} × {1, …, 31} viz: (jan, 1) (jan, 2) … (jan, 30) (jan, 31) (feb, 1)( feb, 2) …(feb, 30)( feb, 31) NB … … … … … (dec, 1)( dec, 2) …(dec, 30)( dec, 31) . Cardinality: #Date = #Month × #Day-Number = 12 × 31 = 372

15

15 Example: Haskell tuples

. Declarations: data Month = Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec type Date = (Month, Int) . Set of values: Date = Month × Integer = {Jan, Feb, …, Dec} × {…, –1, 0, 1, 2, …}

. Application code: tuple construction someday = (jan, 1) component m, d = someday anotherday = (m + 1, d) selection (by pattern matching) 16

16 Mappings (1)

. We write m : S → T to state that m is a mapping from set S to set T. In other words, m maps every value in S to some value in T.

. If m maps value x to value y, we write y = m(x). The value y is called the image of x under m.

. Some of the mappings in {u, v} → {a, b, c}:

m1 = {u → a, v → c} m = {u → c, v → c} 2 image of u is m3 = {u → c, v → b} c, image of v is b

17

17 Mappings (2)

. Let S → T stand for the set of all mappings from S to T: S → T = { m | x ∈ S ⇒ m(x) ∈ T }

. What is the cardinality of S → T? There are #S values in S. Each value in S has #T possible images under a mapping in S → T. #S copies of #T multiplied So there are #T × #T × … × #togetherT possible mappings. . For example,Thus: in {u, v} → {a, b, c} #S there are#( S3 →2 = T )9 =possible (#T) mappings. 18

18 Arrays (1)

. Arrays (found in all imperative and OO PLs) can be understood as mappings. . If an array’s components are of type T and its index values are of type S, the array has one component of type T for each value in type S. Thus the array’s type is S → T. . An array’s length is the number of components, #S. . Basic operations on arrays: so we can select the ith construction of an array from its components • component • indexing – using a computed index value to select a 19 component. 19 Arrays (2)

. An array of type S → T is a finite mapping. . Here S is nearly always a finite range of consecutive values {l, l+1, …, u}. This is called the array’s index rangelower . upper .bound In C and Java, boundthe index range must be {0, 1, …, n–1}. In Ada, the index range may be any primitive (sub)type other than Float.

. We can generalise to n-dimensional arrays. If an array has index ranges of types S1, …, Sn, the array’s type is S1 × … × Sn → T. 20

20 Example: Ada arrays (1)

. Type declarations: type Color is (red, green, blue); type Pixel is array (Color) of Boolean; . Application code: p: Pixel := (true, false, true); c: Color; array … construction p(c) := not p(c); indexin indexin g g

21

21 Example: Ada arrays (2)

. Set of values: Pixel = Color → Boolean = {red, green, blue} → {false, true} viz: {red → false, green → false, blue → false} {red → false, green → false, blue → true} {red → false, green → true, blue → false} {red → false, green → true, blue → true} {red → true, green → false, blue → false} {red → true, green → false, blue → true} {red → true, green → true, blue → false} {red → true, green → true, blue → true}

. Cardinality: 22 #Pixel = (#Boolean)#Color = 23 = 8 22 Example: Ada 2-dimensional arrays

. Type declarations: type Xrange is range 0 .. 511; type Yrange is range 0 .. 255; type Window is array (YRange, XRange) of Pixel; . Set of values: Window = Yrange × Xrange → Pixel = {0, 1, …, 255} × {0, 1, …, 511} → Pixel . Cardinality:

#Window = (#Pixel)#Yrange × #Xrange = 8256 × 512 23

23 2-dimensional arrays in C, Java . achieved by means of nested arrays Pixel[][] . note that the following sets are isomorphic: • Yrange × Xrange → Pixel • Yrange → ( Xrange → Pixel ) . transformation from one to the other is called Currying

24

24 Functions as mappings

. Functions (found in all PLs) can also be understood as mappings. A function maps its argument(s) to its result. . If a function has a single argument of type S and its result is of type T, the function’s type is S → T. . Basic operations on functions: • construction (or definition) of a function • application – calling the function with a computed argument.

. We can generalise to functions with n 25 arguments. If a function has arguments of 25 types S1, …, Sn and its result type is T, the function’s type is S1 × … × Sn → T. Example: Ada functions

. Definition: function is_even (n: Integer) return Boolean is begin or any other return (n mod 2 = 0); code that end; achieves the same effect . Type:  Integer → Boolean

. Value:  {…, 0 → true, 1 → false, 2 → true, 3 → false, …}

. Other functions of same type: is_odd, is_prime, etc. 26

26 Difference between arrays and functions (both correspond to the mathematical notion of mappings) . arrays have finite, enumerable domains . arrays can be modified during execution (are variables) . array domains are usually consecutive • arrays with non-consecutive domains are called associative arrays e.g. Perl (“hashes”), Python • Perl: $count{”gold”} = 4; $count{silver} += 1;

27

27 Disjoint unions (1)

. In a disjoint , a value is chosen from one of several different types. . Let S + T stand for a set of disjoint-union values, each of which consists of a tag together with a variant chosen from either type S or type T. The tag indicates the type of the variant: S + T = { left x | x ∈ S } ∪ { right y | y ∈ T } • left x is a value with tag left and variant x chosen from S • right x is a value with tag right and variant y chosen from T. . Let us write left S + right T (instead of S + T) when we want to make the tags explicit. 28

28 Disjoint unions (2)

. Cardinality: #(S + T) = #S + #T hence the “+” notation . Basic operations on disjoint-union values in S + T: • construction of a disjoint-union value from its tag and variant • tag test, to determine whether the variant was chosen from S or T • projection, to recover either the variant in S or the variant in T.

. Algebraic data types (Haskell), discriminated records (Ada), and objects (Java) can all be understood in terms of disjoint unions.

. We can generalise to multiple variants: S1 + S2 + … + Sn.

29

29