15-312 Recitation #4: Runtime Errors
2002-09-18
Joshua Dunfield (joshuad@cs)
Carnegie Mellon University
We'll take a closer look at runtime errors by adding an explicit
"error" construct.
Recitation outline:
- Review of runtime errors (from lecture)
- Explicit "error"
- Preservation and progress
- The empty type
Review from lecture:
Introduce a new judgment form: "e aborts"
Rules deriving it:
-----------------
div(k1, 0) aborts
e1 aborts
--------------------
apply(e1, e2) aborts
e2 aborts
--------------------
apply(v1, e2) aborts
?: e1 aborts
--------------------
let(e1, x.e2) aborts
e_i aborts
---------------------------------
o(v1,...v_i-1,e_i,...,e_n) aborts
e1 aborts
-------------------
if(e1,e2,e3) aborts
Modify the statement of the Progress theorem:
If |- e : tau
then
(i) e value, or
(ii) e |-> e' for some e', or
[new] (iii) e aborts
Introduce a new construct
error
Add a rule
------------ Abort
error aborts
Now for the typing -- the obvious thing is to say that `error' has
_any_ type:
---------------- ErrorTyp
G |- error : tau
The problem is then to extend the proofs of preservation and progress.
For preservation, there is nothing to be done, since `error' by itself
doesn't step to anything. For progress, recall that the proof was by
rule induction on the derivation of |- e : tau, with one case for
each typing rule. Clearly we must add a case for ErrorTyp, but this
is easy. We need to show error value, or error |-> e' for some e',
or error aborts.
error aborts By Abort
Are we done? No. Why not?
The theorem we're proving has changed (condition (iii)). Therefore,
the IH has changed. We need to look at every application of the IH.
Take the case for IfTyp:
|- e1 : bool |- e2 : tau |- e3 : tau
------------------------------------------ IfTyp
|- if(e1, e2, e3) : tau
The first thing in the proof was to apply the IH:
e1 |-> e1' or e1 value By IH
but now this has changed:
e1 |-> e1' or e1 value or e1 aborts By IH
So we need to handle the subcase in which e1 aborts.
Fortunately, we can apply a rule above to conclude
if(e1, e2, e3) aborts
If we had forgotten that rule, the process of checking
the progress proof would tell us exactly what's needed:
a way to get from e1 aborts to if(e1, e2, e3) aborts.
Note that we no longer have uniqueness of typing, since `error',
`let x = 0 in error end', etc. can be given any type. How could this
be fixed? One way is to change the syntax so the programmer has to
explicitly annotate `error' with the intended type.
We've seen how to add pairs, sums, and a unit type (1) to MinML.
Another (sometimes useful) type is the void type (0), which is
empty -- that is, there is no value v such that
|- v : 0
is derivable. (We can certainly show that `error' has type 0, but
`error' is not a value!) However, there *are* values of type
tau -> 0.
|- fun f(x:int):0 is f x end : int -> 0
Thus, the 0 type gives us a way to characterize non-terminating
expressions.
Note that the "void" type in C and Java is something different,
closest to a unit type 1 (not quite the same: you can't have a C
function that takes two arguments, one of which is void, for example).
Are there values of type int * 0? Intuitively, no.
To prove it, observe that the rule
v1 value v2 value
------------------
(v1, v2) value
is the only rule that can conclude that a pair is a value.
So to construct a pair (v1, v2) of type int * 0, we would
have to construct a value of type 0, which can't be done.