The trap block runs any time an error needs to be handled.
Unlike catch
in other languages, it does not divert the control flow to the
end of the block. Instead, control flow is returned to the line immedately
following where the error was "trapped".
Trapping an error follows a similar syntax to ignoring an error; instead of
using _
, use ?
.
func example() {
{
? = reportAnError()
} trap (err error) {
return err // only happens if err != nil
}
}
An easy way to allow some context would be to place an expression
beside the ?
symbol.
func example() {
{
data, ? "some context" = reportAnError()
} trap (err error, message string) {
// errors.Label() is not part of the errors
// package, but is used here as an example.
return errors.Label(message, err)
}
}
An implementation could allow multiple variables for context. This would change the syntax by requiring either
- brackets and commas
data, ? ctx1; ctx2 = reportAnError()
- semicolons
data, ? (ctx1, ctx2) = reportAnError()
The first would make the grammar much more complicated (I think).
The second looks similar to a ternary operator in other languages, so it may cause confusion.
It is not necessary for the variable "trapped" to be of type error
. When
any interface{}
that is not nil is assigned to ?
, the trap
bock will
be invoked
An implementation may allow multiple variables to be assigned to ?
. An
intuitive behaviour would be for the trap
block to be invoked if any
of those values are not nil, and require the same number of variables
assigned to ?
as the number of variables the trap
block expects.
Example
func example() {
{
?, ? = reportTwoErrors()
} trap (err1, err2 error) {
doSomethingWithErrors(err1, err2)
}
}
A simple implementation would only allow context after the
last ?
symbol.
func example() {
{
?, ? "context"; "more context" = reportAnError()
} trap (err1, err2 error, message, message2 string) {
return errors.Label(message + message2, err1, err2)
}
}
func example() {
{
data1, ? "buy it" := mypkg.buyIt()
data2, err := mypkg.useIt()
if err != nil {
data2, ? "break it" = mypkg.breakIt()
}
} trap (err error, message string) {
return errors.Label(message, err)
}
}
Because the trap block expects (error, string)
, every
assignment with a ?
must have exactly one ?
. The string
would be mandatory, which successfully makes it easier to
report the error with context than without.
Notes:
- Code would not compile if any of the assignments didn't
correspond to trap's signature of
(error, string)