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
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.
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.