An exception is an object used to signal an error or other exceptional situation. The program or run-time system can throw the exception when an error is discovered. An exception handler is a program construct that registers an action to handle exceptions when the handler is active.
If an exception is thrown and not handled then the read-eval-print-loop will print a stack trace, and bring you back to the top level prompt. When not running interactively, an unhandled exception will normally cause Kawa to be exited.
In the Scheme exception model (as of R6RS and R7RS), exception handlers are one-argument procedures that determine the action the program takes when an exceptional situation is signaled. The system implicitly maintains a current exception handler in the dynamic environment. The program raises an exception by invoking the current exception handler, passing it an object encapsulating information about the exception. Any procedure accepting one argument can serve as an exception handler and any object can be used to represent an exception.
The Scheme exception model is implemented on top of the Java VM’s
native exception model where the only objects that
can be thrown are instances of java.lang.Throwable
.
Kawa also provides direct access to this native model,
as well as older Scheme exception models.
Procedure: with-exception-handler
handler
thunk
It is an error if
handler
does not accept one argument. It is also an error ifthunk
does not accept zero arguments. Thewith-exception-handler
procedure returns the results of invokingthunk
. Thehandler
is installed as the current exception handler in the dynamic environment used for the invocation ofthunk
.(call-with-current-continuation (lambda (k) (with-exception-handler (lambda (x) (display "condition: ") (write x) (newline) (k 'exception)) (lambda () (+ 1 (raise ’an-error)))))) ⇒ exception and prints condition: an-error
(with-exception-handler (lambda (x) (display "something went wrong\n")) (lambda () (+ 1 (raise ’an-error)))) prints something went wrong
After printing, the second example then raises another exception.
Performance note: The
thunk
is inlined if it is a lambda expression. However, thehandler
cannot be inlined even if it is a lambda expression, because it could be called byraise-continuable
. Using theguard
form is usually more efficient.
Raises an exception by invoking the current exception handler on
obj
. The handler is called with the same dynamic environment as that of the call to raise, except that the current exception handler is the one that was in place when the handler being called was installed. If the handler returns, thenobj
is re-raised in the same dynamic environment as the handler.If
obj
is an instance ofjava.lang.Throwable
, thenraise
has the same effect asprimitive-throw
.
Procedure: raise-continuable
obj
Raises an exception by invoking the current exception handler on
obj
. The handler is called with the same dynamic environment as the call toraise-continuable
, except that: (1) the current exception handler is the one that was in place when the handler being called was installed, and (2) if the handler being called returns, then it will again become the current exception handler. If the handler returns, the values it returns become the values returned by the call toraise-continuable
.(with-exception-handler (lambda (con) (cond ((string? con) (display con)) (else (display "a warning has been issued"))) 42) (lambda () (+ (raise-continuable "should be a number") 23))) prints: should be a number ⇒ 65
Syntax: guard
variable
cond-clause
+
body
The
body
is evaluated with an exception handler that binds the raised object tovariable
and, within the scope of that binding, evaluates the clauses as if they were the clauses of acond
expression. That implicitcond
expression is evaluated with the continuation and dynamic environment of theguard
expression. If every cond-clause’s test evaluates to#f
and there is noelse
clause, thenraise-continuable
is invoked on the raised object within the dynamic environment of the original call toraise
orraise-continuable
, except that the current exception handler is that of theguard
expression.(guard (condition ((assq 'a condition) => cdr) ((assq 'b condition))) (raise (list (cons 'a 42)))) ⇒ 42(guard (condition ((assq 'a condition) => cdr) ((assq 'b condition))) (raise (list (cons 'b 23)))) ⇒ (b . 23)Performance note: Using
guard
is moderately efficient: there is some overhead compared to using native exception handling, but both thebody
and the handlers in thecond-clause
are inlined.
Procedure: dynamic-wind
in-guard
thunk
out-guard
All three arguments must be 0-argument procedures. First calls
in-guard
, thenthunk
, thenout-guard
. The result of the expression is that ofthunk
. Ifthunk
is exited abnormally (by throwing an exception or invoking a continuation),out-guard
is called.If the continuation of the dynamic-wind is re-entered (which is not yet possible in Kawa), the
in-guard
is called again.This function was added in R5RS.
Returns #t if
obj
is an object raised by theread
procedure. (That is ifobj
is agnu.text.SyntaxException
.)
Returns #t if
obj
is an object raised by inability to open an input or output port on a file. (This includesjava.io.FileNotFoundException
as well as certain other exceptions.)
Procedure: error
message
obj
...
Raises an exception as if by calling
raise
on a newly allocated simple error object, which encapsulates the information provided bymessage
(which should a string), as well as anyobj
arguments, known as the irritants.The string representation of a simple error object is as if calling
(format "#<ERROR ~a~{ ~w~}>"
. (That is themessage
irritants
)message
is formatted as if withdisplay
while each irritantobj
is formatted as if withwrite
.)This procedure is part of SRFI-23, and R7RS. It differs from (and is incompatible with) R6RS’s
error
procedure.
Returns
#t
ifobj
is a simple error object. Specifically, thatobj
is an instance ofkawa.lang.NamedException
. Otherwise, it returns#f
.
Procedure: error-object-message
error-object
Returns the message encapsulated by error-object, which must be a simple error object.
Procedure: error-object-irritants
error-object
Returns a list of the irritants (other arguments) encapsulated by error-object, which must be a simple error object.
These functions associate a symbol with exceptions and handlers: A handler catches an exception if the symbol matches.
Procedure: catch
key
thunk
handler
Invoke
thunk
in the dynamic context ofhandler
for exceptions matchingkey
. If thunk throws to the symbolkey
, thenhandler
is invoked this way:(handler key args ...)
key
may be a symbol. Thethunk
takes no arguments. Ifthunk
returns normally, that is the return value ofcatch
.Handler is invoked outside the scope of its own
catch
. Ifhandler
again throws to the same key, a new handler from further up the call chain is invoked.If the key is
#t
, then a throw to any symbol will match this call tocatch
.
Invoke the catch form matching
key
, passing thearg
s to the currenthandler
.If the key is a symbol it will match catches of the same symbol or of
#t
.If there is no handler at all, an error is signaled.
Procedure: primitive-throw
exception
Throws the
exception
, which must be an instance of a sub-class ofjava.lang.Throwable
.
Syntax: try-finally
body
handler
Evaluate
body
, and return its result. However, before it returns, evaluatehandler
. Even ifbody
returns abnormally (by throwing an exception),handler
is evaluated.(This is implemented just like Java’s
try
-finally
. However, the current implementation does not duplicate thehandler
.)
Syntax: try-catch
body
handler
...
Evaluate
body
, in the context of the givenhandler
specifications. Eachhandler
has the form:var
type
exp
...If an exception is thrown in
body
, the firsthandler
is selected such that the thrown exception is an instance of thehandler
’stype
. If nohandler
is selected, the exception is propagated through the dynamic execution context until a matchinghandler
is found. (If no matchinghandler
is found, then an error message is printed, and the computation terminated.)Once a
handler
is selected, thevar
is bound to the thrown exception, and theexp
in thehandler
are executed. The result of thetry-catch
is the result ofbody
if no exception is thrown, or the value of the lastexp
in the selectedhandler
if an exception is thrown.(This is implemented just like Java’s
try
-catch
.)