Types ===== 1) What is a type? * A type is a set of values * plus an intention: - a low-level representation - a collection of operations that can be applied to those values 1.1) Do you know any language that does not have types? 2) What are the uses of types? - Documentation - Safety - Efficiency - Correctness 2.1) Do types limit the number of programs we can write? 2.2) how would you write this program in Java? int fact(int n) { int f = n; while(--n) <----------\ f *= n; \ return f; | } | | 2.3) Why can't you have this construction in, say, Java? - Java distinguishes integers from booleans * We have two kinds of types: primitive and constructed. 3) What is the difference between them? * Some languages, like Java, define primitive types exactly. Others, like ML or C, don't. 4) What are the primitive types of Java? boolean (false/true) byte (1-byte signed) char (2-byte unsigned) short (2-byte signed) int (4-byte signed) long (8-byte signed) float (4-byte floating point) double (8-byte floating point) 4.1) What about C? char (signed/unsigned) short (signed/unsigned - int) int (signed/unsigned) long (signed/unsigned - int) float double 4.2) How to discover the maximum integer in C? #include #include int main() { printf("%d\n", INT_MAX); } - or - #include int main(int argc, char** argv) { unsigned int i = ~0U; printf("%d\n", i); i = i >> 1; printf("%d\n", i); } $> a.out -1 2147483647 4.3) What about SML? - Int.maxInt; val it = SOME 1073741823 : int option - or - E.g: use "fun sum a b = a + b handle Overflow => 0;" as an example. fun maxInt current inc = maxInt (current + inc) (inc * 2) handle Overflow => if inc = 1 then current else maxInt current 1 * Constructed types are just sets built from other sets. 5) What is the simplest constructed set? Or, what is the simplest way to build a set from another set? 5.1) How to declare enumerations in C? // enum.c #include enum coin { penny = 1, nickel = 5, dime = 10, quarter = 25 }; int main() { printf("%d\n", penny); printf("%d\n", penny + 1); printf("%d\n", penny + 4 == nickel); } 5.2) What about SML? - datatype day = M | Tu | W | Th | F | Sa | Su; - fun isWeekend x = (x = Sa orelse x = Su); 6) What is another way to build sets? * Some languages support true tuple types: fun get1 (x : real * real) = #1 x; - get1 (3.4, 4.3); val it = 3.4 : real 7) How to implement tuples in C? // complex.c #include struct complex { double rp; double ip; }; int main() { struct complex c1; c1.rp = 0; printf("%d\n", c1.rp); printf("%d\n", c1.ip); } * named record types are tuples indexed by names, instead of numeric indices. SML has those too: type complex = { rp:real, ip:real }; fun getip (x : complex) = #ip x; * Types have an internal representation. Some languages hide it from programmers, others don't. 8) How are tuples arranged in memory in C? 8.1) How to iterate on the fields of a tuple of integers in C? #include struct mySt { int i1, i2, i3, i4, sentinel; }; int main(int argc, char** argv) { struct mySt s; int *p1, *p4; s.i1 = 1; s.i2 = 2; s.i3 = 3; s.i4 = 4; p1 = ( (int*) &s); p4 = &(s.sentinel); do { printf("field = %d\n", *p1); p1++; } while (p1 != p4); } 9) Which other sets can we talk about? - Vectors are a multidimensional cartesian product of the same set. 9.1) Which types do we derive from vectors? - arrays, lists, strings. 9.2) What is an array? * indices vary: Java starts from 0, Pascal is more flexible. 10) How does the implementation of vectors change from one language to the other? - What are the index values? - Is array size fixed at compile time (part of static type)? - Which operations are supported? - Is redimensioning possible at runtime? - Are multiple dimensions allowed? - Is a higher-dimensional array the same as an array of arrays? - What is the order of elements in memory? - Is there a separate type for strings (not just array of characters)? - Is there a separate type for lists? 10.1) Which operations on arrays can we carry out in R? X <- c(1, 2, 3) Y <- c(4, 5, 6) 2 * X X * Y X %*% Y ... etc ... 11) Which other way to build a set are we missing? 11.1) What is the difference between union and cartesian product? 11.2) How to represent union in C? // element.c #include union element { int i; float f; }; int main() { union element e; e.f = 177689982.02993F; printf("Int = %d\n", e.i); printf("Float = %f\n", e.f); e.f = 0.0F; e.i = 177689982; printf("Int = %d\n", e.i); printf("Float = %f\n", e.f); } 11.3) How are unions implemented in C? * In ML we represent unions via datatypes: datatype element = I of int | F of real; fun getReal (F x) = x | getReal (I x) = real x; 11.4) What's the cardinality of a union type? 12) Which type is missing now? * Functions map a given set, the domain, into another set, the range. 13) How would be this function below in SML? int f(char a, char b) { return a==b; } - fun f (a:char, b) = a = b; 13.1) Which operations can we perform on functions? fun comp c a b = c (a, b); fun ci (a:real, b) = not (a > b orelse a < b); comp ci 2.3 4.5 14) When to check the types used in a program? - At compilation time. - At execution time. 14.1) Examples of statically typed language? 14.2) Examples of dynamically typed languages? 14.3) Examples of a type error in C? 14.4) Examples of a type error in ML? 14.5) Examples of a type error in Python? 15) How to determine the types of values in a program during compilation? - Type annotations. - Naming conventions: e.g: I for integer in Fortran, and S$ for strings in Basic. - Type inference: Haskell, ML, Scala, Ocaml, C#3.0 15.1) Can anyone give me examples of type inference in Java? double a; sysout(a*0); 16) What is the advantage of dynamically typed languages? 16.1) Can someone give me an example? def fact(n): if (n > 0): return n * fact(n-1) else: return 1 >>> type(fact(10)) >>> type(fact(100)) - or - def div(a, b): if (b == 0): return "Argh!!!" else: return a / b >>> div(3.14, 4) 0.785 >>> div(3.14, 0) 'Argh!!!' 17) How a dynamically typed language would be implemented? * It is not black and white: - Statically typed languages do some dynamic checks. 18) Examples in Java? class Pencil { public int p; } public class Battleship { public int p; public static void main (String[] args) { Object p = new Pencil(); Battleship b = (Battleship)p; // Check happens here!!! } } - Dynamically typed languages use a bit of type inference. * Some languages allow runtime type tests. 19) Can anyone give me an example? * There exists languages which are strongly typed, and languages which are weakly typed. - A strongly typed language guarantees that a type will be always used as declared. 20) Can anyone give me an example? - A weakly typed language allows a value to be used as if it had a type different from its declaration type. 20.1) Examples? 20.2) Examples of unsafe type usage in C? union element { int i; float f; }; int main() { union element e; e.f = 17.0; printf("%lf\n", e.i); } - or - int main() { int a[3] = {1, 2, 3}; printf("%d\n", a[3]); } 20.3) What does this program print? #include #include int offset(char *p, char *q) { return (int)q - (int)p; } int main() { char *p = malloc(4); char *q = malloc(4); q[2] = 0; int index = offset(p, q+2); p[index] = 1; printf("%d\n", q[2]); } 21) Can anyone give me an example of unsafe C++ code? 21.1) What is the code below going to print? #include #include struct Pencil { int p; }; struct Battleship { int b; }; int main () { Pencil *p = new Pencil(); p->p = 17; Battleship *b = new Battleship(); b->b = 11; printf("p->p = %d, b->b = %d\n", p->p, b->b); b = (Battleship*)p; printf("p->p = %d, b->b = %d\n", p->p, b->b); } 22) Can anyone give me an example of unsafe memory protection in C? // iterStruct2.c int main() { char* s = "Hello!"; char* s1 = "Fernando!"; char* s2 = "Magno!"; char* s3 = "Quintao!"; char* s4 = "Pereira!"; char* c = s; int i; for (i = 0; i < 41; i++) { printf("%c", *c); c++; } printf("\n"); } 22.1) What would happen if I had replaced the loop by: for (i = 0; i < 41; i++) { printf("%c", *c); *c = 'a'; c++; } 23) When are two types equivalent? - There are two ways to decide: name equivalence and structural equivalence: Ex.: SML - type irpair1 = int * real; type irpair1 = int * real - type irpair2 = int * real; type irpair2 = int * real - fun f(x:irpair1) = #1 x; val f = fn : irpair1 -> int - val (y:irpair2) = (3, 3.14); val y = (3,3.14) : irpair2 - f y; val it = 3 : int 23.1) What about C++? // See also UnsafeCoerc.cpp #include #include struct Pencil { int p; }; struct Battleship { int b; }; int main () { Pencil *p = new Pencil(); Battleship *b = p; printf("p->p = %d, b->b = %d\n", p->p, b->p); }