Difference between revisions of "Language Reference/Terms/Try-catch-finally"
< Language Reference | Terms
m (subarticle) |
|||
(9 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
The try-catch-finally statement provides | The try-catch-finally statement provides means for dealing with exceptions that may occur in a given block of code. | ||
<vipbnf><TryCatchTerm>: | <vipbnf><TryCatchTerm>: | ||
Line 11: | Line 11: | ||
<Term></vipbnf> | <Term></vipbnf> | ||
The | A try-construction thus have a <vpbnf>Term</vpbnf> and a list of catch and finally handlers. | ||
The <vpbnf><Term></vpbnf> and the handlers are not allowed to leave backtrack points (i.e. they cannot have mode <vp>multi</vp> or <vp>nondeterm</vp>). | |||
A try-construction with more than one handler is equivalent to nesting several try-constructions with one handler each. I.e. the following term: | |||
<vipbnf>try | <vipbnf>try | ||
<Body> | <Body> | ||
catch < | catch <Var1> do | ||
<Handler1> | <Handler1> | ||
finally | finally | ||
<Handler2> | <Handler2> | ||
catch <Var2> do | |||
<Handler3> | |||
end try</vipbnf> | |||
Is equivalent to these nested terms: | |||
<vipbnf>try | |||
try | |||
try | |||
<Body> | |||
catch <Var1> do | |||
<Handler1> | |||
end try | |||
finally | |||
<Handler2> | |||
end try | |||
catch <Var2> do | |||
<Handler3> | |||
end try</vipbnf> | |||
==== try-catch ==== | |||
Consider the try-catch construction | |||
<vipbnf>try | |||
<Body> | |||
catch <Var> do | |||
<Handler> | |||
end try</vipbnf> | end try</vipbnf> | ||
First <vpbnf><Body></vpbnf> is evaluated. | |||
If <vpbnf><Body></vpbnf> fails or succeeds the whole try construction fails or succeeds, respectively. I.e. if <vpbnf><Body></vpbnf> does not terminate with an exception the try construction corresponds to evaluating <vpbnf><Body></vpbnf>. | |||
If <vpbnf><Body></vpbnf> terminates with an exception, then the exception is caught by the catch handler. Meaning that first <vpbnf><Var></vpbnf> is bound to the exception (in PFC context the exception will be a <vp>traceId</vp>) and then <vpbnf><Handler></vpbnf> is evaluated. In this case the construction behaves as if <vpbnf><Handler></vpbnf> is evaluated with <vpbnf><Var></vpbnf> bound to the caught exception. | |||
Notice, that no bindings are made by <vpbnf><Body></vpbnf> if it terminates with an exception. | |||
{{Example| Handle the situation where a file cannot be read: | |||
<vip>clauses | |||
read(Filename) = Contents :- | |||
try | |||
Contents = file::readFile(Filename) | |||
catch TraceId do | |||
stdio::writef("Could not read the file: %\n", Filename), | |||
exceptionDump::dumpToStdio(TraceId), | |||
Contents = "" | |||
end try.</vip> | |||
First <vp>Contents = file::readFile(Filename)</vp> is evaluated, if that does not terminate with an exception <vp>read</vp> returns the contents of the file. | |||
If it raises an exception the handler is evaluated with <vp>TraceId</vp> bound to the exception. So in this case a message is written to <vp>stdio</vp> and then the exception is dumped to <vp>stdio</vp>, and finally <vp>Contents</vp> is set to the empty string which is returned as result. | |||
}} | |||
==== try-finally ==== | |||
Consider the try-finally construction: | |||
<vipbnf>try | <vipbnf>try | ||
<Body> | |||
finally | finally | ||
<Handler> | |||
end try</vipbnf> | end try</vipbnf> | ||
The purpose of the construction is to evaluate the <vpbnf><Handler></vpbnf> after the <vpbnf><Body></vpbnf> no matter how the <vpbnf><Body></vpbnf> terminates, i.e. whether it succeeds, fails or terminates with an exception (it cannot leave backtrack points). | |||
The evaluation is like this | |||
First <vpbnf><Body></vpbnf> is evaluated. | |||
* If <vpbnf><Body></vpbnf> succeeds: <vpbnf><Handler></vpbnf> is executed and the try-finally construction succeeds. | |||
* If <vpbnf><Body></vpbnf> fails: <vpbnf><Handler></vpbnf> is executed and the try-finally construction fails. | |||
* If <vpbnf><Body></vpbnf> terminates with an exception <vpbnf><Exn></vpbnf>: <vpbnf><Handler></vpbnf> is executed and the try-finally construction terminates with the exception <vpbnf><Exn></vpbnf>. | |||
{{Example| Ensure that an <vp>odbcStatement</vp> is <vp>free</vp>'d after use: | |||
<vip>clauses | |||
tryGetName(Connection, PersonId) = Name :- | |||
Stmt = odbcStatement::new(Connection), | |||
try | |||
Stmt:setParameterValue(1, core::integer(PersonId)), | |||
Stmt:execDirect("select name from person where id=?"), | |||
Stmt:fetch(), | |||
Name = Stmt:getParameterValue_string(1) | |||
finally | |||
Stmt:free() | |||
end try.</vip> | |||
The <vp>Stmt</vp> is <vp>free</vp>'d also if <vp>fetch</vp> fails, or if something terminates with an exception. | |||
}} | |||
<noinclude>{{LanguageReferenceSubarticle|Terms/Try-catch-finally}}</noinclude> |
Latest revision as of 10:39, 12 February 2013
The try-catch-finally statement provides means for dealing with exceptions that may occur in a given block of code.
TryCatchTerm: try Term CatchFinally-list end try CatchFinally: one of catch Variable do Trap-Handler finally Finally-Handler Handler: Term
A try-construction thus have a Term and a list of catch and finally handlers.
The Term and the handlers are not allowed to leave backtrack points (i.e. they cannot have mode multi or nondeterm).
A try-construction with more than one handler is equivalent to nesting several try-constructions with one handler each. I.e. the following term:
try Body catch Var1 do Handler1 finally Handler2 catch Var2 do Handler3 end try
Is equivalent to these nested terms:
try try try Body catch Var1 do Handler1 end try finally Handler2 end try catch Var2 do Handler3 end try
try-catch
Consider the try-catch construction
try Body catch Var do Handler end try
First Body is evaluated.
If Body fails or succeeds the whole try construction fails or succeeds, respectively. I.e. if Body does not terminate with an exception the try construction corresponds to evaluating Body.
If Body terminates with an exception, then the exception is caught by the catch handler. Meaning that first Var is bound to the exception (in PFC context the exception will be a traceId) and then Handler is evaluated. In this case the construction behaves as if Handler is evaluated with Var bound to the caught exception.
Notice, that no bindings are made by Body if it terminates with an exception.
clauses read(Filename) = Contents :- try Contents = file::readFile(Filename) catch TraceId do stdio::writef("Could not read the file: %\n", Filename), exceptionDump::dumpToStdio(TraceId), Contents = "" end try.
First Contents = file::readFile(Filename) is evaluated, if that does not terminate with an exception read returns the contents of the file.
If it raises an exception the handler is evaluated with TraceId bound to the exception. So in this case a message is written to stdio and then the exception is dumped to stdio, and finally Contents is set to the empty string which is returned as result.
try-finally
Consider the try-finally construction:
try Body finally Handler end try
The purpose of the construction is to evaluate the Handler after the Body no matter how the Body terminates, i.e. whether it succeeds, fails or terminates with an exception (it cannot leave backtrack points).
The evaluation is like this
First Body is evaluated.
- If Body succeeds: Handler is executed and the try-finally construction succeeds.
- If Body fails: Handler is executed and the try-finally construction fails.
- If Body terminates with an exception Exn: Handler is executed and the try-finally construction terminates with the exception Exn.
clauses tryGetName(Connection, PersonId) = Name :- Stmt = odbcStatement::new(Connection), try Stmt:setParameterValue(1, core::integer(PersonId)), Stmt:execDirect("select name from person where id=?"), Stmt:fetch(), Name = Stmt:getParameterValue_string(1) finally Stmt:free() end try.
The Stmt is free'd also if fetch fails, or if something terminates with an exception.