CSC362 2011F, Class 27: Type Checking (2) Type Equivalence Overview: * Why Type Check? * Detour: Type Coercion in C. * Type Equivalence: Subranges and Enumerated Types. * Type Equivalence; Records. Admin: * Are there questions on phase 3 of the project? * Try to ask questions before Sunday. * Are there questions in preparation for Friday's examination? * I will do max of grades on each problem * EC for Jin Feng's talk tomorrow at 4:15 p.m. * Sam has a confusing schedule for the next week due to prereg. Check online at http://www.cs.grinnell.edu/~rebelsky/Schedule/signup.2011F.txt Why Type Check? - Why figure out types? * Correctness - If you use the 'wrong' type at a point in the program, you are probably making a mistake float f; a[f] = 3.2; * A broader programming issue: If you switch types, you may change accuracy. * E.g., coerce an int to a float and then back to an int * Code generation z := x + y * Need an add instruction, but there are different types of adds Add immediate (includes constant) vs "normal add" * Different types require different instructions "Add int" vs "Add float" * Coercion/conversion Type Coercion in C I thought you might enjoy this quote from Kernighan & Ritchie (2nd edition, p. 198). --- BEGIN QUOTE --- Many operators cause conversions and yield result types in a similar way. The effect is to bring operands into a common type, which is also the type of the result. This pattern is called the usual arithmetic conversions First, if either operand is a long double, the other operand is converted to a long double. Otherwise, if either operand is a double, the other is converted to double. Otherwise, if either operand is a float, the other is converted to float. Otherwise, the integral promotions are performed on both operands; then, if either operand is unsigned long int, the other is converted to unsigned long int. Otherwise, if one operand is long int and the other is unsigned int, the effect depends on whether a long int can represent all values of an unsigned int; if so, the unsigned int operand is converted to long int; if not, both are converted to unsigned long int. Otherwise, if one operand is long int, the other is converted to long int. Otherwise, if one operand is unsigned int, the other is converted to unsigned int. Otherwise, both operands have type int. ---- END OF QUOTED MATERIAL ---- * Maybe implicit coercion is too complicated, and we shouldn't support it * But "real" programmers don't like explicit coercion char str[STRLEN]; int c; while ((c = getchar ()) != SENTINEL) str[i++] = c; The issue: getchar () needs to return something other than a character when we have a special situation; e.g. EOF (-1). Other solutions: * Sacrifice a character. * Throw an exception (not in C) * SIGNALS! * Precondition testing "getchar () can only be called when the input is not at the end of file. You can check whether you are at the end of file with eofp ()." * Set a global variable c = getchar (); if (getchar_ok) .. Note: There are different kinds of coercion * We aren't changing how the value is stored; we're changing what bits are looked at * Alternate: Change how it is represented in memory or how memory is interpreted Type Equivalence and Enumerated Types * If I have two variables, x and y, of "different" types, when can I legally assign y to x? * In C, see the coercion description above for a partial answer. type day = (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday); weekday = Monday .. Friday; daynum = 0..6; grade = 0..100; var d: day; w: weekday; n: daynum; g: grade; i: integer; d := w; // YES: weekday is a subset of day, so this should be okay w := d; // NO: What should we do if d is Saturday? // YES: There are times in which you want to do this assignment // and know that it's safe. // // d is 'Preferred day to work'. If the person prefers // // a weekday, we give it to them. Otherwise, we make them // // work on the least preferred weekday. // if (Monday <= d) and (d <= Friday) // w := d; // else // w := Monday; // You might allow w := (weekday) d; // What happens if the cast is illegal? // In both cases, what do you do at RUNTIME if it's invalid // You might have to generate code to do runtime checking // You might allow invalid results // Class consensus: Make it illegal // In C // enum foo = { a, b, c }; // enum bar = { d, e, f }; // foo fo; bar ba; // fo = ba; i := g; // YES: Smaller to larger // NO: i can be used for things other than grades, and // this might lead us to use a grade as, say, an index // when we're not planning to do so. g := i; // NO: See analysis above // What about g := 43; // What about g := grade(43); d := n; // YES, they have the same integer representation // NO, different types implies different underlying goals // Allow explicit coercion // NO, we should be able to choose different representations // and not let the programmer look "under the hood" n := d; // Similar General principle: * If they have the same underlying representation, allow it * If they are declared differently, and are not subsets, disallow it Type Equivalence and Record Types type t0 = record a: integer; b: integer end; t1 = record a: integer; b: real end; t2 = record a: integer; b: real end; t3 = record b: real; a; integer end; t4 = record c: integer; b: real end; t5 = record a: integer; b: real; c: integer; end; t6 = t1; var v0: t0; v1: t1; v2: t2; v3: t3; v4: t4; v5: t5; v6: t6; v7: record a: integer; b: real end; v8,v9: record a: integer; b: real end;