Download presentation
Presentation is loading. Please wait.
1
Type Checking and Type Inference
cs776 (Prasad) L3Type
2
Motivation Application Programmers Language Implementers Reliability
Logical and typographical errors manifest themselves as type errors that can be caught mechanically, thereby increasing our confidence in the code execution. Language Implementers Storage Allocation (temporaries) Generating coercion code Optimizations Type checking : Compile time vs run-time (e.g., Pascal vs Scheme) Declare types for constants and variables, infer types for composite expressions (e.g., Java) Declare types for constants (and variables only to resolve ambiguity), infer types for variables and composite expressions (e.g., ML) cs776 (Prasad) L3Type
3
Evolution of Type System
Weak typing C Arrays (bounds not checked), Union type Actuals not checked against formals. Data Abstraction Ada Type is independent of representation details. Generic Types Compile-time facility for “container” classes. Reduces source code duplication. Typeless Assembly language Any instruction can be run on any data “bit pattern” Implicit typing and coercion FORTRAN Explicit type declarations Pascal Type equivalence C has pointers that can be used as integers and vice versa. cs776 (Prasad) L3Type
4
Languages Strongly typed (“Type errors always caught.”)
Statically typed (e.g., ML, Ada, Eiffel, etc) Compile-time type checking : Efficient. Dynamically typed (e.g., Scheme, Smalltalk, etc) Run-time type checking : Flexible. Weakly typed (e.g., C) Unreliable Casts (int to/from pointer). Object-Oriented Languages such as Eiffel, Java, etc impose restrictions that guarantee type safety and efficiency, but bind the code to function names at run-time. 1. Strongly typed languages guarantee that all type incompatibilities are caught by the compiler and/or run-time system. 2. Statically typed languages factor out all type checking at compile-time. No run-time overhead implies efficiency. “Type of entity = Type of object” 3. Dynamically typed languages check compatibility of the type of the operation with the type tags of the operand values at run-time. This approach is flexible (consider heterogeneity and genericity), but each run is penalized. “Entities are typeless, while values are tagged.” 4. In OOPLs, if T is the type of an entity, then it can hold a reference to an object of subclass of T. cs776 (Prasad) L3Type
5
Type inference is abstract interpretation.
( ) / int * int -> int / (ML-error) real * real -> real 2.0 ( int int ) / real int / real real Computing the type of a subexpression is akin to evaluating the subexpression. x: real i,j: int ( j + i ) * x int * real real In SML97, (1+4)/2.5 is not type correct, while real(1+4)/2.5 is. That is, it requires explicit type casting. Typically, for a binary operation among n different types, one needs n*n implementations of the op. We can accomplish the same using n “homogeneous” implementations and n coercion functions. Languages differ in how they introduce coercion. In C++/Java, it is implicit in some situations, and explicit in others. In SML and Ada, it is always explicit. cs776 (Prasad) L3Type
6
Expression Grammar: Type Inference Example
E -> E + E | E * E | x | y | i | j Arithmetic Evaluation x, y in {…, -1.1, …, 2.3, …} i, j in {…, -1,0,1,…} +, * : “infinite table” Type Inference x, y : real i, j : int cs776 (Prasad) L3Type
7
Values can be abstracted as type names
and arithmetic operations can be abstracted as operations on these type names. +, * defined on infinite sets and described as an infinite table. cs776 (Prasad) L3Type
8
Type correctness is neither necessary nor sufficient for programs to run.
if true then 5 else 0.5 Not type correct, but runs fine. if true then 1.0/0.0 else 3.5 Type correct, but causes run-time error. cs776 (Prasad) L3Type
9
Assigning types to expressions
Uniquely determined fn s => s ^ “.\n”; val it = fn : string -> string Over-constrained (type error) ( ) Under-constrained Overloading fn x => fn y => x + y; (* resolvable *) fn record => #name(record); (* error *) Polymorphism fn x => 1 ; val it = fn : 'a -> int Maximizing Generality and Flexibility; Constraint satisfaction; (unique solution; unsatisfiable; multiple solution (describable uniquely, no simple description) ) Haskell uses class hierarchy to deal with overloading (syntactic; semantic connection not required). Both Haskell and ML support polymorphism (semantic). cs776 (Prasad) L3Type
10
rdivc : real -> real -> real fun rdivu (x,y) = x / y
Type Signatures fun rdivc x y = x / y rdivc : real -> real -> real fun rdivu (x,y) = x / y rdivu : real * real -> real fun plusi x y = x + y plusi : int -> int -> int fun plusr (x:real,y) = x + y plusr : real * real -> real Older SML gave an error for the last definition because there is ambiguity in the type of x and y. In SML97, int is taken as the default in such cases. cs776 (Prasad) L3Type
11
Polymorphic Types Semantics of operations on data structures such as stacks, queues, lists, tables, etc are independent of the component type. Polymorphic type system provides a natural representation of generic data structures without sacrificing type safety. Polymorphism fun I x = x; I 5; I “x”; for all types a: I: a -> a C++ templates are not type checked, rather instantiations are checked at run-time. Ada generics avoid source code duplication and are amenable to type checking, but instantiation of generics may result in duplication of object code for each component type. LISP/Scheme use dynamic typing : operations verify types when run. Java 5 compiler maps generics to the older classes with Object (type erasure) for ensuring backward compatibility. Polymorphic functions have signatures involving type variables. I (5,2.5) ; I “x”; int*int -> int*int; string -> string cs776 (Prasad) L3Type
12
Composition val h = f o g; fun comp f g = let fun h x = f (g x) in h;
“Scope vs Lifetime : Closure” comp: (a -> b) -> (l->a) -> (l->b) Generality Equality constraints Higher-order functions; infix binary composition o Op o = comp val f = fn : int -> int - val g = f; val g = fn : int -> int - val h = f o g; val h = fn : int -> int cs776 (Prasad) L3Type
13
map-function fun map f [] = [] | map f (x::xs) = f x :: map f xs
map : (a -> b) -> (a list) -> (b list) map (fn x => 0) [1, 2, 3] map (fn x => x::[]) [“a”, “b”] list patterns; term matching. definition by cases; ordering of rules Polymorphic function on fixed-type list : typing constraints Alpha, beta imply for all types, but alpha and beta can be different (not must be different). Homogeneous lists. cs776 (Prasad) L3Type
14
Conventions f g h = ( ( f g ) h )
Function application is left-associative. f g h = ( ( f g ) h ) -> is right-associative. int->real->bool = int->(real->bool) :: is right-associative. a::b::c::[] = a::(b::(c::[]) Function application binds stronger than ::. f x :: xs = ( f x ) :: xs (a -> b) -> (b -> c) =/= (a -> b -> b -> c) Meaningful/convenient defaults cs776 (Prasad) L3Type
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.