8.20 Try

  1. try Exprs
  2. catch
  3. Class1:ExceptionPattern1[:Stacktrace] [when ExceptionGuardSeq1] ->
  4. ExceptionBody1;
  5. ClassN:ExceptionPatternN[:Stacktrace] [when ExceptionGuardSeqN] ->
  6. ExceptionBodyN
  7. end

This is an enhancement of catch. It gives the possibility to:

  • Distinguish between different exception classes.
  • Choose to handle only the desired ones.
  • Passing the others on to an enclosing try or catch, or to default error handling.Notice that although the keyword catch is used in the try expression, there is not a catch expression within the try expression.

It returns the value of Exprs (a sequence of expressions Expr1, …, ExprN) unless an exception occurs during the evaluation. In that case the exception is caught and the patterns ExceptionPattern with the right exception class Class are sequentially matched against the caught exception. If a match succeeds and the optional guard sequence ExceptionGuardSeq is true, the corresponding ExceptionBody is evaluated to become the return value.

Stacktrace, if specified, must be the name of a variable (not a pattern). The stack trace is bound to the variable when the corresponding ExceptionPattern matches.

If an exception occurs during evaluation of Exprs but there is no matching ExceptionPattern of the right Class with a true guard sequence, the exception is passed on as if Exprs had not been enclosed in a try expression.

If an exception occurs during evaluation of ExceptionBody, it is not caught.

It is allowed to omit Class and Stacktrace. An omitted Class is shorthand for throw:

  1. try Exprs
  2. catch
  3. ExceptionPattern1 [when ExceptionGuardSeq1] ->
  4. ExceptionBody1;
  5. ExceptionPatternN [when ExceptionGuardSeqN] ->
  6. ExceptionBodyN
  7. end

The try expression can have an of section:

  1. try Exprs of
  2. Pattern1 [when GuardSeq1] ->
  3. Body1;
  4. ...;
  5. PatternN [when GuardSeqN] ->
  6. BodyN
  7. catch
  8. Class1:ExceptionPattern1[:Stacktrace] [when ExceptionGuardSeq1] ->
  9. ExceptionBody1;
  10. ...;
  11. ClassN:ExceptionPatternN[:Stacktrace] [when ExceptionGuardSeqN] ->
  12. ExceptionBodyN
  13. end

If the evaluation of Exprs succeeds without an exception, the patterns Pattern are sequentially matched against the result in the same way as for a case expression, except that if the matching fails, a try_clause run-time error occurs.

An exception occurring during the evaluation of Body is not caught.

The try expression can also be augmented with an after section, intended to be used for cleanup with side effects:

  1. try Exprs of
  2. Pattern1 [when GuardSeq1] ->
  3. Body1;
  4. ...;
  5. PatternN [when GuardSeqN] ->
  6. BodyN
  7. catch
  8. Class1:ExceptionPattern1[:Stacktrace] [when ExceptionGuardSeq1] ->
  9. ExceptionBody1;
  10. ...;
  11. ClassN:ExceptionPatternN[:Stacktrace] [when ExceptionGuardSeqN] ->
  12. ExceptionBodyN
  13. after
  14. AfterBody
  15. end

AfterBody is evaluated after either Body or ExceptionBody, no matter which one. The evaluated value of AfterBody is lost; the return value of the try expression is the same with an after section as without.

Even if an exception occurs during evaluation of Body or ExceptionBody, AfterBody is evaluated. In this case the exception is passed on after AfterBody has been evaluated, so the exception from the try expression is the same with an after section as without.

If an exception occurs during evaluation of AfterBody itself, it is not caught. So if AfterBody is evaluated after an exception in Exprs, Body, or ExceptionBody, that exception is lost and masked by the exception in AfterBody.

The of, catch, and after sections are all optional, as long as there is at least a catch or an after section. So the following are valid try expressions:

  1. try Exprs of
  2. Pattern when GuardSeq ->
  3. Body
  4. after
  5. AfterBody
  6. end
  7.  
  8. try Exprs
  9. catch
  10. ExpressionPattern ->
  11. ExpressionBody
  12. after
  13. AfterBody
  14. end
  15.  
  16. try Exprs after AfterBody end

Next is an example of using after. This closes the file, even in the event of exceptions in file:read/2 or in binary_to_term/1. The exceptions are the same as without the try…after…end expression:

  1. termize_file(Name) ->
  2. {ok,F} = file:open(Name, [read,binary]),
  3. try
  4. {ok,Bin} = file:read(F, 1024*1024),
  5. binary_to_term(Bin)
  6. after
  7. file:close(F)
  8. end.

Next is an example of using try to emulate catch Expr:

  1. try Expr
  2. catch
  3. throw:Term -> Term;
  4. exit:Reason -> {'EXIT',Reason}
  5. error:Reason:Stk -> {'EXIT',{Reason,Stk}}
  6. end