灰色区域:well behaved
红色区域:ill behaved
如果所有程序都是灰的,strongly typed
如果存在红色的程序,weakly typed
编译时排除红色程序,statically typed
运行时排除红色程序,dynamically typed
所有程序都在黄框以外,type safe
A program variable can assume a range of values during the execution of a program. An upper bound of such a range is called a type of the variable.
Languages where variables can be given (nontrivial) types are called typed languages.
Languages that do not restrict the range of variables are called untyped languages: they do not have types or, equivalently, have a single universal type that contains all values.
A type system is that component of a typed language that keeps track of the types of variables and, in general, of the types of all expressions in a program.
A language is typed by virtue of the existence of a type system for it, whether or not types actually appear in the syntax of programs. Typed languages are explicitly typed if types are part of the syntax, and implicitly typed otherwise.
It is useful to distinguish between two kinds of execution errors: the ones that cause the computation to stop immediately, and the ones that go unnoticed (for a while) and later cause arbitrary behavior. The former are called trapped errors, whereas the latter are untrapped errors.
An example of an untrapped error is improperly accessing a legal address, for example, accessing data past the end of an array in absence of run time bounds checks. Another untrapped error that may go unnoticed for an arbitrary length of time is jumping to the wrong address: memory there may or may not represent an instruction stream.
Examples of trapped errors are division by zero and accessing an illegal address: the computation stops immediately (on many computer architectures).
A program fragment is safe if it does not cause untrapped errors to occur. Languages where all program fragments are safe are called safe languages.
Therefore, safe languages rule out the most insidious form of execution errors: the ones that may go unnoticed.
Untyped languages may enforce safety by performing run time checks. Typed languages may enforce safety by statically rejecting all programs that are potentially unsafe. Typed languages may also use a mixture of run time and static checks.
Typed languages usually aim to rule out also large classes of trapped errors, along with the untrapped ones.
For any given language, we may designate a subset of the possible execution errors as forbidden errors. The forbidden errors should include all of the untrapped errors, plus a subset of the trapped errors.
A program fragment is said to have good behavior, or equivalently to be well behaved, if it does not cause any forbidden error to occur.
In particular, a well behaved fragment is safe.
A language where all of the (legal) programs have good behavior is called strongly checked.
Thus, with respect to a given type system, the following holds for a strongly checked language:
(1) No untrapped errors occur (safety guarantee).
(2) None of the trapped errors designated as forbidden errors occur.
(3) Other trapped errors may occur; it is the programmer’s responsibility to avoid them.
Typed languages can enforce good behavior (including safety) by performing static (i.e., compile time) checks to prevent unsafe and ill behaved programs from ever running. These languages are statically checked; the checking process is called typechecking, and the algorithm that performs this checking is called the typechecker. A program that passes the typechecker is said to be well typed; otherwise, it is ill typed, which may mean that it is actually ill-behaved, or simply that it could not be guaranteed to be well behaved.
Untyped languages can enforce good behavior (including safety) in a different way, by performing sufficiently detailed run time checks to rule out all forbidden errors. (For example, they may check all array bounds, and all division operations, generating recoverable exceptions when forbidden errors would happen.) The checking process in these languages is called dynamic checking; LISP is an example of such a language. These languages are strongly checked even though they have neither static checking, nor a type system.
Even statically checked languages usually need to perform tests at run time to achieve safety. For example, array bounds must in general be tested dynamically. The fact that a language is statically checked does not necessarily mean that execution can proceed entirely blindly.
By our definitions, a well behaved program is safe. Safety is a more primitive and perhaps more important property than good behavior. The primary goal of a type system is to ensure language safety by ruling out all untrapped errors in all program runs. However, most type systems are designed to ensure the more general good behavior property, and implicitly safety. Thus, the declared goal of a type system is usually to ensure good behavior of all programs, by distinguishing between well typed and ill typed programs.
In reality, certain statically checked languages do not ensure safety. That is, their set of forbidden errors does not include all untrapped errors. These languages can be euphemistically called weakly checked (or weakly typed, in the literature) meaning that some unsafe operations are detected statically and some are not detected.
Type UnTyped
Safe ML,Java LISP
UnSafe C Assembler
Formal type systems are the mathematical characterizations of the informal type systems that are described in programming language manuals. Once a type system is formalized, we can attempt to prove a type soundness theorem stating that well-typed programs are well behaved. If such a soundness theorem holds, we say that the type system is sound. (Good behavior of all programs of a typed language and soundness of its type system mean the same thing.)
In this chapter we discuss type systems independently of semantics. It should be understood, though, that ultimately a type system must be related to a semantics, and that soundness should hold for that semantics.