Condition Handlers¶
Handling errors in Idio works differently to many programming
languages. In those, when an exception is raised then the computation
state is unwound to where the handler is and the handler is executed
and control continues from after the exception handling block. Think
try
/except
in Python.
In Idio, when a condition is raised the VM pauses the current computation with all of the extant computation intact and walks back through the execution state looking to see if any handlers have been established for this condition type (or an ancestor of this condition type).
If one is found the associated handler is called with the condition as an argument which can do a number of things:
it can return a value in which case that value is used in place of the errant computation and the original computation continues as if the errant computation had returned whatever the handler has just returned
This isn’t used by the Idio defined error handlers as the conditions are not normally something easily recoverable from. There is an example below of unwise intervention.
It also requires that the handler have some intimate knowledge of the state of processing at the time of the error.
Suppose you wrote an ^i/o-no-such-file-error handler around a call to open-file. The expectation of the calling code is to receive an open file handle and so, if you want to handle the missing file by “quickly creating and opening another file” in its stead to return the open file handle, you also need to return the correct type of file (input or output) and with the correct mode.
it can raise the condition again with a view that a previously established handler can take care of the problem
The state computation is unchanged, the outer handler can still return a value.
it can raise a totally different condition
The state computation is unchanged, the outer handler, handling a different condition, can still return a value to the original point of failure.
it can emulate the execution stack unwinding (
try
/except
) by calling trap-return in the handler
You can establish handlers in two ways:
trap establishes a handler for a condition type (or types) around a block of code
set-default-handler! establishes a handler for a condition type
In that sense,
set-default-handler!
is much more like the shell’strap
builtin.
If you don’t do anything you will find there are several handlers established by default, including:
an ^rt-command-status-error handler, default-rcse-handler
If an external program fails then this handler will normally cause idio to exit in the same manner. There are some mitigations.
a ^condition handler, default-condition-handler
This looks to see if a handler for the condition’s type has been established with
set-default-handler!
and, if so, runs it.a ^condition handler, restart-condition-handler
This attempts to unwind the current state of execution to the most recent top level expression and runs its continuation.
a ^condition handler, restart-condition-handler
This attempts to exit cleanly.
Attention
This should be straight-forward but somehow isn’t.
Example Handler¶
Suppose we want to handle ^rt-divide-by-zero-error:
trap ^rt-divide-by-zero-error (function (c) {
; we could generate a scathing report with
; condition-report "fool!" c
; return a value indicating the
; user's foolishness
'fool
}) {
1 / 0
}
Hmm, nothing. Well, technically, trap
itself will have returned
the symbol fool
.
Suppose the body was more complex and went on to use the returned value:
trap ^rt-divide-by-zero-error (function (c) {
'fool
}) {
t := 1 / 0
1 + t
}
This shows our handler as being incredibly naïve as now we get an
^rt-parameter-type-error in the next
expression as the addition, +
, won’t accept the symbol as a valid
type.
We can revert to the more common try
/expect
behaviour by
returning from the trap
itself with trap-return:
trap ^rt-divide-by-zero-error (function (c) {
trap-return 'fool
}) {
t := 1 / 0
1 + t
}
Here, we return the symbol fool
from trap
as soon as the
divide-by-zero error occurs and without stumbling into the problem
with addition.
Handler Functions¶
- template trap conditions handler body¶
Establish a handler handler for conditions conditions around body
- Param conditions:
a condition type or a list of condition types
- Type conditions:
symbol or a list of symbols
- Param handler:
the handler
- Type handler:
1-ary function
- Param body:
the body
- Type body:
expression
trap
may not return.Normally,
trap
will return whatever body returns – usually body is a block and so the value of the last expression evaluated.If a condition is raised during the processing of body then
trap
may (eventually) continue processing body if a handler returns a value in place of the condition-raising expression.trap
will therefore return the value of the last expression evaluated, as normal.The condition handler may be restart-condition-handler in which case the current top-level expression is discarded and its continuation is run.
The condition handler may be reset-condition-handler in which case the idio process will attempt to exit.
- template trap-return [v]¶
return v to the continuation of trap
- Param v:
the value to return, defaults to
#<void>
- Type v:
any, optional
- template suppress-errors! conditions body¶
Establish a handler (that returns
#<void>
) for conditions conditions around body- Param conditions:
a condition type or a list of condition types
- Type conditions:
a condition type or a list of condition types
- Param body:
the body expression
- Type body:
expression
Attention
suppress-errors!
has a very narrow use case. In general, returning a value to failed computations requires intimate knowledge of the computation.However,
suppress-errors!
is used exclusively with ^system-error in situations where there is a race condition between the parent and child after a libc/fork which results in one or the other failing.
Standard Handlers¶
- function default-SIGCHLD-handler c¶
The default handler for an
^rt-signal-SIGCHLD
conditionThis invokes do-job-notification.
- Param c:
the condition
- Type c:
condition instance
- function default-racse-handler c¶
The default handler for an
^rt-async-command-status-error
condition- Param c:
the condition
- Type c:
condition instance
- Return:
#<unspec>
The default behaviour is to report but otherwise ignore failed asynchronous processes
See also
suppress-async-command-report! for means to change the default behaviour.
- function default-rcse-handler c¶
The default handler for an
^rt-command-status-error
condition- Param c:
the condition
- Type c:
condition instance
- Return:
see below
If the command exits with a non-zero status (from exit(3) or by signal) then we exit the same way.
Otherwise
#<unspec>
See also
suppress-exit-on-error! and suppress-pipefail! for means to change the default behaviour.
- function default-condition-handler c¶
Invoke the default handler for condition c
If there is no default handler: - if the session is interactive then the debugger is invoked - otherwise the condition is re-raised
- Param c:
the condition
- Type c:
condition instance
does not return per se
- function set-default-handler! ct handler¶
set the default handler for condition type ct to handler
If a condition of type ct is not otherwise handled then handler will be invoked with the continuation.
- Param ct:
condition type
- Type ct:
condition type
- Param handler:
handler for the condition type
- Type handler:
function
- Return:
#<unspec>
- function clear-default-handler! ct¶
unset the default handler for condition type ct
The default behaviour for conditions of type ct will resume.
- Param ct:
condition type
- Type ct:
condition type
- Return:
#<unspec>
- function restart-condition-handler c¶
Restart the VM with the continuation of the current top-level expression.
- Param c:
the condition
- Type c:
condition instance
does not return per se
Warning
restart-condition-handler
is only effective if the session is interactive
- function reset-condition-handler c¶
Stop the VM and exit non-zero.
- Param c:
the condition
- Type c:
condition instance
Does not return.
Last built at 2025-01-10T07:10:38Z+0000 from 62cca4c (dev) for Idio 0.3.b.6