CS 541 Lecture -*-Outline-*- * Type Systems (Ch. 7) this is a hot topic in language design ** monomorphism (7.1) Def: each name has exactly one type. e.g., most of Pascal Q: Why would it be bad if in Pascal one had to use several different write procedures (writeint, writechar, ...)? ** overloading (7.2) also called ad hoc polymorphism Q: Does overloading really "not increase expressive power"? Q: What is the difference between overloading and polymorphism? parametericity Consistency (regularity) principle: if the language can do it, programmer should be able to. (so if language can overload, ...) Q: How are different overloadings of an identifier distinguished? Q: Which is better: context-independent or context-dependent overloading? Why? Q: Does a language have to prohibit ambiguous expressions? what if it can guarantee that you'll get the same result either way. Q: Should the overloadings of an identifier be related? Why? If so, how? (This is a research question...) ** parametric polymorphism (7.3) *** polymorphic abstraction (7.3.1) Q: What does the type of a polymorphic function look like? discuss the "forall" interpretation of type variables Q: Why are polymorphic functions so useful in functional programming? *** parameterized (or polymorphic) types (7.3.2) Q: Is a type parameter different than a type variable? Q: Could we write the type of hd just using type variables? no -- parameterized types give structure *around* type vars. *** polytypes (7.3.3) Q: What is the syntactic difference between a poolytype and a monotype? Q: In what sense is a polytype the intersection of types it can derive? Q: Are there any other functions besides id that have type all T . T -> T? Q: What functions are in the type all T . T -> Truth-value ? Q: What functions are in the type all T . Truth-Value -> T ? Q: Why is the identity function the only function of type all T . T -> T? because there is nothing else to work with ** type inference (7.4) preferred term nowdays is "type reconstruction" a feature of ML Q: how does type inference work? by solving systems of simultaneous constraint equations *** examples see 7.13, 7.15 and papers in reading list ----------------- fun double(f) = (fn (x) => f(f(x))); --------------- double : 'a -> 'b 'b = 'c -> 'd x : 'c f : 'a = ... 'c -> 'c --------------- val add2 = double(fn x: int => x + 1); val id = double(reverse); --------------- check these ** coercions (7.5) Def: a coercion is a map form one type to another that is applied *implicitly* in appropriate program contexts Q: What coercions does C have? C++? Q: Why don't coercions fit well with overloading? Q: Why don't coercions fit well with polymorphism? coercions are also frowned upon because they may introduce hidden computation (esp. in a loop) ** subtypes and inheritance (7.6) Warning: This is what I think about a lot. If types are sets of values, then subtypes are subsets. e.g., 0..3 is a subtype of integer Q: Can we declare the primes as a subset of the integers? Q: Is there any problem with not knowing a unique type for values? (overloading) *** inheritance Inheritance: if S is a subtype of T, then operations of T apply to S. I prefer to call this subtype polymorphism keep inheritance for code reuse (def of class by stating diffs) discuss example 7.19 why don't we want area inherited? can we be surprised if we think a parameter is a point and apply area to it? *** subtyping Distinction between subtype and subclass: need spec to decide subtyping (a behavioral notion) *** semantics for records to get subtype = subset Q: does this seem reasonable? if model records as functions from labels to values, does it still work? Q: is bool a subtype of int? can't we construct the same kind of model? doesn't seem like it's trustworthy, as can get bool subtype of int Q: Can we derive rules for function type subtyping from the idea that subtype = subset? illustration adapted from Cardelli's typeful programming ------------------ FUNCTION SUBTYPING _______AC________ _______BD________ | | | | | _____A_____ | | _____D_____ | | | | | | | | | | | a * | | | | d * | | | |__________| | | |__________| | | c * | | b * | |________________| |________________| ------------------ Let the type A = {a}, AC = {a,c}, BD = {b,d}, D = {d} Consider the function type A -> BD If you were expecting to use a function of type A -> BD, then you could use one of type AC -> D See diagram below -------------------- BD ^^ / | inclusion map g / | AC---/-->D ^ / | / this exists by composition | / A -------------------- So get the rule -------------------- A subtype of AC, D subtype of BD ____________________________ (AC -> D) subtype of (A -> BD) -------------------- Although this is the correct rule and makes sense, it doesn't follow from the subtype = subset analogy: (AC -> D) = {{(a,d)}, {(c,d)}} (A -> BD) = {{(a, b)}, {(a,d)}} but note that (AC -> D) is NOT a subset of (A -> BD) To get the correct rule and preserve subtype = subset, have to adopt much more complex model of function types (the Ideal model, for example) J. Reynolds (and I) don't think subtypes need to be subsets.