introduction this presentation is modeled on a paper by luca cardelli (bell labs, 1985) a general...

30

Upload: logan-mccormick

Post on 28-Dec-2015

213 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the
Page 2: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Introduction This presentation is modeled on a paper by Luca

Cardelli (Bell Labs, 1985)

A general view of type-checking will be presented from the perspective of the programming language designer

We will explore type systems past, present and future

Page 3: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

A little history Type systems have been around longer than computers In the 1920s David Hilbert started a program to formalize

mathematics as strings of symbols manipulated by logic/grammar rules Idea was to be able to “mechanically” prove things

Bertrand Russell understood the problems with self-reference and approached Hilbert’s challenge by assigning entities to types Entities of each type are built up from entities of the preceding type

In 1931 Kurt Gödel proved that consistent systems of any complexity are incomplete, ending Hilbert’s program

Application to programming languages Computing involves representing and manipulating entities as strings of

symbols Problems of representation and self-reference crop up in numerous ways We want to mechanically prove things about programs Types support this

Page 4: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

What are types, really? Types come into play whenever we have a

universe of diverse things with a similar representation Bits in a computer’s memory

XML strings

DNA

If you consider these things in the absence of a type system, you have an “untyped universe” This means there is really only one type (the memory

word, the DNA base pair, etc.)

Page 5: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Operations in untyped universes Any such universe has various operations that can be performed:

Adding and subtracting (bit strings)

Rendering HTML (XML)

Transcription/translation (DNA)

But these operations are only valid on subsets of the untyped universe Some XML strings represent HTML documents and some don’t

Some DNA sequences represent valid genes and some don’t

What happens if you blow it? Tumbolia, the land of dead hiccups and extinguished lightbulbs

(Douglas Hofstadter)

The major purpose of a type system is to avoid embarrassing questions about representations, and to forbid situations where these questions might come up (Cardelli)

Page 6: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Type-checking and programming languages

Type-checking avoids these embarrassing questions Assigns types to constants, operators, variables, and functions

Checks that every operation is performed on inputs of the correct type

Accepts programs that can be proven to have no type errors

Type-checker reads program code and says “ok” or“not ok and here’s why”

By comparison An interpreter reads program code and executes the

instructions

A compiler reads program code and translates it into a different representation of the same program

Page 7: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Type systems in programming languages The term type system refers to the range of types that can

be assigned to variables and values Base types: int, float, double, etc.

User-defined types (e.g. classes, parameterized types, etc.)

Type systems are somewhat arbitrary, and inspired largely by the typical instruction sets of modern computers

You can create different type systems for the same language that are more or less expressive Inexpressive type systems are frustrating; they either accept too

many erroneous programs, or forbid too many correct ones

Expressive type systems are more precise, rejecting as many erroneous programs as possible and accepting a greater percentage of correct ones

Page 8: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Expressiveness and abstract data types Imagine a type system that supports only the types int and

object Now you’re compiling this function:

int foo (object o){

return o.bar();}

Does the type system say yes or no? If yes, we’re overly permissive – the type-checker doesn’t know whether

the “bar” method is really available If no, we’re overly restrictive

The type system needs to be more expressive – needs to include separate types for each class, etc.

Expressiveness means having a rich language of types enabling the type-checker to determine with the greatest possible precision whether it should accept programs or not

Page 9: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Polymorphism and type inference Polymorphism gives type-checkers an even bigger headache

Requires a major increase in expressiveness What is the type of a generic List class? What is the type of a generic Sort function?

Type checking is simplified by having programmers annotate programs with type information However this gets painful as the type system becomes expressive Solution is type inference – let the computer figure out all the types

The goal of type-checking research:

Maximize the expressiveness of type systems while minimizing the need for programmers to annotate programs with complex type information

Page 10: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Examples The best way to explore the subtleties of type

systems is to work through examples

Let’s try a few…

Page 11: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Subtyping

class Base {};

class Derived : public Base {};

void main(char* args[]){

Base *b = new Derived ();Derived *d = b;

}

Is this typesafe?

Should it be accepted by the compiler?

If you add a dynamic cast (i.e. add further annotations to help the compiler), will the compiler add a runtime check? Should it?

Page 12: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Apples and oranges// from one header file

struct Apple { int x;};

void appleProcessingService (Apple* a) {}

// from another header file

struct Orange { int x;};

// source file

void main(char* args[]){

appleProcessingService (new Apple()); appleProcessingService (new Orange ());}

Is this typesafe? Should it be accepted by the compiler? Why (or why not)?

Page 13: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

How about this one?// from header file, US edition of software

struct Apple { int x;};

void appleProcessingService (Apple* a) {}

// from header file, French edition of software

struct Pomme { int x;};

// source file

void main(char* args[]){

appleProcessingService (new Apple());appleProcessingService (new Pomme());

}

Is this typesafe? Should it be accepted by the compiler? Why (or why not)?

Page 14: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Math expressionsvoid main (char* args[]){ int x = 123; int y = 234; int z = x / y;}

Is this typesafe? Should it be accepted by the compiler?

Page 15: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Wouldn’t it be cool if… We had a “rational” datatype?

void main (char* args[]){ int w = 123; int x = 234; rational y = w / x; rational z = w ^ 0.5; }

Any problems here?

Page 16: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

What kind of error is this?

void main (char* args[]){ int x = 1; int y = 0; int z = x / y;}

Could type systems help us here?

Page 17: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

What if we introduced … A “nonzero” datatype?

Say the compiler requires the divisor to be of type “nonzero”:

void main (char* args[]){ int x = 1; nonzero y = 0; int z = x / y;}

Good idea? Or not?

Page 18: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Fibonacci strikes back Is this typesafe? Could a type-checker prove it?

nonzero fib (int x) {if (x < 2) {

return 1;} else {

return fib(x-1) + fib(x-2);}

}

How about this?

int inputAndParseNumberFromUser () {}

void main (char* args[]){ nonzero x = inputAndParseNumberFromUser ();}

Options?

Page 19: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

User-constructed types Data abstraction implies the ability for programmers to create new types

How do we express the type of variable foo in this example?struct {

int x;

float y;

} foo;

Type theorists usually write the type something like this:(int, float)

The type of an array of integers would be:[int]

An array of arrays of integers would be:[[int]]

The type of a function with an int argument returning a float would be:int → float

Page 20: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

User-constructed types The operators (), [], and → are type constructors

They take types as arguments and define new types

Once you have type constructors, your type system can contain as many types as you like Type-checker has to cope with all of this, providing a

syntax for programmers to write all these types If necessary

Page 21: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Polymorphism When introducing polymorphic constructs into the language, type constructors

are not enough

Type of the Length function for arrays of integers: [int] → int

Type of the Length function for arrays of anything: forall (T) { [T] → int }

Introducing polymorphic types into a type system is analogous to introducing functions into a programming language

The above type could also be written: forall (U) { [U] → int }

U is a type variable and “forall” provides type abstraction

Use of “forall” is called universal quantification because any type can be plugged in to U

Polymorphic types can be specialized: type V = forall (U) { [U] → int } type W = V<string>

Page 22: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Why have type notation? Why do we feel the need to write out these

complicated types? If you’re writing a function, you only need to write

the types of the return value and arguments, not the function itself

Two reasons: If you’re programming with higher order functions (which

we’ll be doing more of in the future) it’s helpful to write these types

These functions do have types, regardless of whether we’re writing them out – it would be nice to have a standard notation

Page 23: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Bounded quantification Bounded quantification is the idea that that only some

types can be plugged in to U

For example, if you had a Length function which could only be used on arrays of different kinds of numbers, you could write: type T = forall (U :: U <= number) { [U] → int }

U is constrained to be a number (or subtype thereof)

But what if you do this? type V = T<string>

Is that a type mismatch?

Page 24: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Types and kinds In the spirit of Russell, computer scientists generally like to keep

these levels separate. Higher-level types which ensure correctness of types are called “kinds”

This level of checking is referred to as “kind checking”

There are countless papers floating around with titles like

“Is type a type?”and

“A new programming language with type : type”

They are exploring the question of whether a type system can operate on itself, or whether levels should be kept separate.

Page 25: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

C++ bounded quantification question

template <typename T> class Copier {

T myStruct; public:

void copy () { myStruct.x = myStruct.y; }};

struct IntPair { int x, y; };struct FloatPair { float x, y; };struct BogusPair { float x; char* y; };

void main(char* args[]){

Copier<IntPair> cip;cip.copy();

Copier<FloatPair> cfp;cfp.copy();

Copier<BogusPair> cbp; // cbp.copy();

}

Page 26: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Existential quantification The type of a function that takes an array of T and returns an

integer, for some single type T:exists(T) { [T] → int }

At this point we have implicitly defined a type T We know nothing about type T, except that…

A function of the above type could take a list of them and return an int

T is intuitively a little like a class It is a type, and we don’t know anything about how it works, but we know

a way in which we can use it

Universal and bounded quantification provide the theoretical basis for parameterized types

Existential quantification provides the theoretical basis for information hiding

Page 27: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Type inference As type systems become more complicated, it

becomes more burdensome for programmers to write out types

Would you write expressions like this?forall (U :: U <= number) { [U] → int } myFunction (…) {

}

No – you would just avoid higher order functions

The solution is type inference

Page 28: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Type inference Allows programmers to omit type declarations and have

the compiler infer them Promises all of the expressiveness of dynamic

languages, but with static type safety Research in this area has come a long way – but there

are still valid, type-safe programs which type inference engines cannot handle

Rudimentary type inference (local variables) is coming in .NET 3.0

Given that type theory experts like Simon Peyton-Jones are at Microsoft we can expect to see this area of .NET evolve rapidly

Page 29: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Ideas for the future Continue improving type system expressiveness and type

inference engines

How about having the type-checker interact with the programmer? e.g.○ “Can I assume this will always be an odd number?”

○ “Can I assume that no instances of this class are constructed outside of this source tree?”

How about monitoring running programs to generate better type annotations for use in future compilations?

How about a graphical interface for creating and manipulating type information

Page 30: Introduction  This presentation is modeled on a paper by Luca Cardelli (Bell Labs, 1985)  A general view of type-checking will be presented from the

Conclusion Type-checking is not a simple, tidy field It’s a matter of tradeoffs and judgment More expressiveness means that programming

languages can become more powerful and polymorphic without compromising type safety

However more expressiveness = more pain for programmers Working with higher-order functions is great, but not if you have

to type 10 lines of type declarations for each line of code

Type inference is a promising solution Holy grail is to provide all the power of dynamic languages like

Lisp, Python, and Ruby with the type safety of C++ and no need to write a single type declaration