Annotation of researchv10no/cmd/sml/doc/refman/exceptions.tex, revision 1.1.1.1

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.

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.