|
|
1.1 root 1: \chapter{Exceptions}
2: \label{exception}
3: The rough and ready rule for understanding how exceptions are handled
4: is as follows. If an exception is raised by a \verb"raise"
5: expression
6: \begin{quote}
7: \verb"raise" $E$ \verb"(" {\it exp} \verb")"
8: \end{quote}
9: which lies in the textual scope of a declaration of the exception
10: constructor $E$, then it may be handled by a handling rule
11: \begin{quote}
12: \verb"handle" $E$ \verb"(" {\it pat} \verb") =>" {\it exp'}
13: \end{quote}
14: but only if this handler is in the textual scope of the same
15: declaration.
16:
17: Any exception, regardless of scope, is handled by a wildcard or
18: variable pattern, as
19: \begin{quote}
20: \verb"handle _ =>" {\it exp'}
21: \end{quote}
22: This rule is perfectly adequate for exceptions declared at top level;
23: some examples in Section~\ref{pathexn} below illustrate what may occur in other
24: cases.
25:
26: \section{An example}
27: To illustrate the generality of exception handling, suppose we have
28: declared some exceptions as follows:
29: \begin{verbatim}
30: exception Oddlist of int and Oddstring of string
31: \end{verbatim}
32: and that a certain expression exp:int may raise either of these
33: exceptions and also runs the risk of dividing by zero. The handler
34: in the following \verb"handle" expression would deal with these
35: expressions:
36: \begin{verbatim}
37: exp handle Oddlist [] => 0
38: | Oddlist [x] => 2*x
39: | Oddlist (x::y::_) => x div y
40: | Oddstring "" => 0
41: | Oddstring s => size(s)-1
42: | Div => 10000
43: \end{verbatim}
44: Note that the whole expression is well-typed because in each handling
45: rule the type of the match-pattern is \verb"exn", and because the
46: result type of the match is \verb"int", the same as the type of exp.
47:
48: Note also that the last handling rule will handle \verb"Div"
49: exceptions raised by exp, but will not handle the \verb"Div"
50: exception that may be raised by \verb"x div y" in the third handling
51: rule. Finally, note that a universal handling rule
52: \begin{verbatim}
53: | _ => 50000
54: \end{verbatim}
55: at the end would deal with all other exceptions raised by exp.
56:
57: \section{Exception constructors}
58: For an exception constructor E, the expression
59: \begin{quote}
60: $E$ \verb"(" {\it exp} \verb")"
61: \end{quote}
62: evaluates the expression {\it exp}, producing value $v$,
63: and then applies the constructor $E$ to it, yielding the value
64: $E(v)$, whose type is \verb"exn".
65:
66: The \verb"raise" keyword may be applied to any expression of type
67: \verb"exn", and has the effect of ``raising'' that exception value.
68: The innermost (dynamically) enclosing expression
69: $e = e_1~\verb"handle"~m_1$ is found; all further evaluation of the
70: expression $e_1$ (and its subphrases) is aborted; and the match $m_1$
71: is applied to the exception value, yielding the result of the
72: expression $e$.
73:
74: If the match in a handler fails, then the exception value is
75: \label{reraise}
76: re-raised, and another enclosing handler is found.
77:
78: Exception constructors may be nullary (have no associated value), in
79: which case the {\it exp} and {\it pat} in the previous discussion are
80: omitted.
81:
82: Exceptions may be constructed independently of raising them:
83: \begin{verbatim}
84: exception A of int
85: val e = A 6
86: val x = raise e
87: \end{verbatim}
88: Handlers may be abstracted from the \verb"handle" keyword:
89: \begin{verbatim}
90: val h = fn E 0 => "zero"
91: | E _ => "nonzero"
92: | v => raise v
93:
94: f(x) handle e => h e
95: \end{verbatim}
96: Note that it is advisable in this case to have a default clause in
97: the function \verb"h", since the default for a \verb"handle" match
98: (re-raising the exception) is different from the default for a \verb"fn" or
99: \verb"case" match (raising the \verb"Match" exception).
100:
101: The ordinary wildcard pattern
102: \verb"_" will handle any exception when it is used in a pattern, as
103: will any pattern consisting solely of a variable. These should be
104: used with some care, bearing in mind that they will even handle
105: interrupts.
106:
107: Nullary exception names, when misspelled, appear to the compiler to be
108: variables; these will then match any exception. For this reason we
109: recommend the convention that exception names (and other
110: constructors) be written beginning with an uppercase character, and
111: variables be written beginning with a lowercase character. The
112: compiler may remind the programmer of this convention when it is
113: violated.
114:
115: \section{Some pathological examples}
116: \label{pathexn}
117: We now consider some possible misuses of exception handling, which
118: may arise from the fact that exception declarations have scope, and
119: that each evaluation of a generative exception binding creates a
120: distinct exception. Consider a simple example:
121: \begin{verbatim}
122: exception E of bool
123: fun f(x) =
124: let exception E of int
125: in if x > 100 then raise E(x) else x+1
126: end
127: val z = f(200) handle E(true) => 500 | E(false) => 1000
128: \end{verbatim}
129: The program is well-typed, but useless. The exception bound to the
130: outer \verb"E" is distinct from that bound to the inner \verb"E";
131: thus the exception raised by \verb"f(200)", with excepted value 200,
132: could only be handled by a handler within the scope of the inner
133: exception declaration---it will not be handled by the handler in the
134: program, which expects a boolean value. So this exception will be
135: reported at top level. This would apply even if the outer exception
136: declaration were also of type int; the two exceptions bound to
137: \verb"E" would be distinct.
138:
139: On the other hand, if the last line of the program is changed to
140: \begin{verbatim}
141: f(200) handle _ => 500
142: \end{verbatim}
143: then the exception will be caught, and the value 500 returned. A
144: universal handling rule (i.e. \verb"_" or a variable-identifier)
145: catches any exception---even one exported from the scope of the
146: declaration of the associated exception name---but cannot examine the
147: excepted value carried by the exception constructor, since the type
148: of this value cannot be statically determined.
149:
150: Even a single textual exception binding---if for example it is
151: declared within a recursively defined function---may bind distinct
152: exceptions to the same identifier. Consider another useless program:
153: \begin{verbatim}
154: fun f(x) =
155: let exception E
156: in if p(x) then a(x)
157: else if q(x) then f(b(x)) handle E => c(x)
158: else raise E
159: end
160: val z = f v
161: \end{verbatim}
162: Now if p(v) is false but q(v) is true, the recursive call will
163: evaluate f(b(v)). Then if both p(b(v) and q(b(v)) are false, this
164: evaluation will raise \verb"E". But this exception will not be
165: handled, since the exception raised is that which is bound to
166: \verb"E" by the inner---not outer---evaluation of the exception
167: declaration.
168:
169: These pathological examples should not leave the impression that
170: exceptions are hard to use or to understand. The rough and ready
171: rule of Section~\ref{exception} will almost always give the correct
172: understanding.
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.