Language Reference/Terms/Try-catch-finally

From wiki.visual-prolog.com

< Language Reference‎ | Terms

Revision as of 10:51, 5 November 2008 by Thomas Linder Puls (talk | contribs) (Example Template)

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.

Example Handle the situation where a file cannot be read:
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.
Example Ensure that an odbcStatement is free'd after use:
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.