Types and Type Systems: Understanding the Basics of Type Checking and Inference, Study notes of Programming Languages

An overview of types in programming languages, including the classification of values, basic and compound types, type checking and inference, and the importance of types in modern programming. It covers topics such as type declarations, type errors, and the relative type-safety of different languages.

Typology: Study notes

Pre 2010

Uploaded on 07/30/2009

koofers-user-rgj
koofers-user-rgj 🇺🇸

9 documents

1 / 23

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
cs3723 1
Types
Classification of Values
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17

Partial preview of the text

Download Types and Type Systems: Understanding the Basics of Type Checking and Inference and more Study notes Programming Languages in PDF only on Docsity!

Types

Classification of Values

Outline

 General discussion of types

 What is a type? What is it used for?

 Basic vs. compound types; What is a type constructor?

 Type systems; type errors; type safety of languages

 Type declarations and type equivalence

 Type checking and type inference

 Compile-time vs run-time type checking

 Type environment and scopes

 Compile-time type checking and type inference

 Polymorphism

 Polymorphism vs overloading

 Uniform vs non-uniform impl of polymorphism

Types in Programming

 A type is a collection of computable values

 Represent concepts from problem domain  Accounts, banks, employees, students  Represent different implementation of values  Integers, strings, floating points, lists, records, tuples …

 Languages use types to

 Support organization of concepts  Separate types for separate concepts from problem domain  Identify and prevent errors  Compile-time and run-time type checking  Prevent meaningless computation 3 + true - “Bill”  Support efficient translation (by compilers)  Short integers require fewer bits  Access record component by a known offset  Use integer units for integer operations

Values and Types

 Basic types: types of atomic values

 int, bool, character, real, symbol

 Values of different types

 have different layouts  have different operations

 Explicit vs. implicit type conversion of values

 Compound types: types of compound values

 List, record, array, tuple, struct, ref, pointer

 Built from type constructors

 int arr[100]  arr: array(int,100)  (3, 4, “abc”) : int * int * string  int *x  x : pointer(int)int f(int x) { return x + 5}  f : intint

Type Error

 When a value is misinterpreted or misused with unintended semantics, a type error occurs

 May cause hardware error

function call x() where x is not a function

 may cause jump to instruction that does not contain

a legal op code

 May simply return incorrect value

int_add(3, 4.5)

 not a hardware error

 bit pattern of 4.5 can be interpreted as an integer

 just as much an error as x() above

Relative type-safety of

languages

 BCPL family, including C and C++

 Not safe: casts, pointer arithmetic, …

 Algol family, Pascal, Ada

 Almost safe  Dangling pointers:  Pointers to locations that have been deallocated  No language with explicit de-allocation of memory is fully type- safe

 Type-safe languages with garbage collection

 Lisp, ML, Smalltalk, Java  Dynamically typed: Lisp, Smalltalk  Statically typed: ML, JAVA

Static vs. Dynamic Typing

 In Lisp, we can write function like

(lambda (x) (if (number? x) (+ x 1) (car x)))

x could be a number or a list.

if x is a symbol, a type error will occur  cannot apply car

to x

Some uses will produce type error, some will not

 Static typing is always conservative

 Must define a different function for each input type

int f1 (int x) { return x + 1; }

int f2 (Intlist x) { return first_elem(x); }

do we need a different function for floating point lists?

Compile-time vs Run-time Type Checking

 Run-time type checking (Lisp/Scheme, perl)

Example: in Lisp/Scheme, when evaluating each (car x)

 Check to make sure x is a non-empty list

 Compile-time type checking (ML, Java, C++/C)

Example: ML has strong type inference f(x)

 In C/C++/Java, if a function f is declared int f(float x)

 Value x must have type float

 Both prevent type errors

 Run-time checking slows down execution

 Compile-time checking restricts program flexibility

Lisp list: elements can have different types ML list: all elements must have the same type

 Combination of compile and runtime checking

 Example: Java (array bound check at runtime)

Type checking and type

inference

 Type checking

int f(int x) { return x+1; };

int g(int y) { return f(y+1)*2;};

 Programmer has to declare the types of all variables

 Compilers evaluate the types of expressions and check

agreement

 Type inference

int f(int x) { return x+1; };

int g(int y) { return f(y+1)*2;};

 Programmers are not required to declare types for

variables

 Compilers try to figure out agreeable types of all

expressions

 Find most general type by solving constraints  Lead to polymorphism

Find Type Errors Without Running the Program

 Types of variables

 Each variable must have a single type

 It can hold only values of this type

 Types of expressions

 Every expression must have a single type

 It maps input values to a return value  It can return only values of this type

 Type system

 Rules for deciding types of expressions

 These rules specify the proper usage of each operator

 Accept only expressions that can be typed according to

rules

 Explicit vs. implicit type conversion

Type Checking

 Given an expression, if we know the type of each

variable, what is the type of the expression?

(define (Add exp num) (cond ((null? exp) exp) ((cons? exp) (cons (Add (car exp) num) (Add (cdr exp) num))) ( (number? exp) (+ exp num)) (else exp)))

Suppose we know the type of each variable in a symbol table

((exp ‘int) (num ‘int))

What is the type of (Add exp num)?

(null? exp)  false (cons? exp)  false (number? exp)  true (+ exp num)  ‘int

Type Checking

 In C/C++

int f (int a, int b, int c) { return a + b + c; }

((a int) (b int) (c int))  (a+b+c) : int

 In Scheme

(lambda (a b c) (+ a b c)) ((a int) (b int) (c int))  (a+b+c) : int ((a float) (b int) (c int))  (a + b + c) : float ((a list) (b int) (c int))  (a + b + c): type_error

 In statically typed languages (ML, C,C++,Java)

 Each variable has a single type  each expression has a single type

 In dynamically typed languages (Lisp/Scheme)

 Each variable may have different types depending on the running context  each expression may have different types

Type Inference

 In C/C++: suppose we don’t need to declare variables

f (a, b, c) { return a + b + c; } +: intintint  a: int; b: int; c: int; a + b + c : int +: floatfloatfloat  a : float; b : float; c : float; …  type error

 In Scheme: expressions could have multiple types

(lambda (a b c) (+ (+ a b) c)) +: number*numbernumber  a: number; b : number; c : number; (+ a b) : number

 In statically typed languages (ML, C, C++, Java)

 When each operator has a single type definition, we can automatically infer types of variables and expressions  When each operator has multiple type definitions (evaluation rules), type inference can easily fail  An operator is overloaded if it has multiple type definitions

Type Inference

 Another example in Scheme

(define f (lambda (x) (+ 2 x)))

> f: int → int

 How does it work

 + has two types: intint->int, realreal->real

 2 : int has only one type

 This implies + : int*int -> int

 Therefore, need x : int

 Therefore f(x:int) = 2+x has type int → int

+ is overloaded because it has two types. Most operators in a static type system have a single type In many cases, unique type may be polymorphic.