Protected execution is q’s model of exception handling. If you are familiar with exception models (such as try, catch, and throw) from another language, you will notice a resemblance.
In any exception handling model, there is a block of code to attempt to execute and one or more blocks of code to invoke should the attempted block fail. Moreover, the error handling blocks have a proscribed form. Lastly, there is a mechanism to raise an exception.
Let’s look at a simple example in q and break it down:
LaidBackLoad: {[file] @[{system "l ", x; 1b}; / code to attempt file; / argument {[err] 0N! err; 0b}]} / error handler
In q, there is only one error handling block, and both the try block and the error handling block must be functions. In addition, the error handler takes a single parameter, which – if the error handler is called – will be a string.
In our example, the function to try takes only a single parameter, and that’s why the protected execution expression starts with an @. If your try function takes more than one parameter, use . instead:
LaidBackEqual: { .[{x = y}; / code to attempt (x; y); / arguments {[err] 0N! err; 0b}]} / error handler
You signal an error (which may be a symbol or a string) using the ‘ (signal) operator:
CantBeNegative: {if [x < 0; ‘ “Must be >= 0”]; x}
This is exactly the same mechanism that q uses to let us know when we have done something wrong:
q)(1 2 3) = 1 2
‘length
q)
There is one last detail to note when reviewing the above examples. Protected execution expressions are expressions, and they have a value. If the try function does not signal, then the expression’s value is the try function’s return value. Otherwise, the protected execution expression’s value is the value returned by the error handler.