Refining TRY exceptions
An refinement to try has been suggested (for a quite a while): to provide a way to distinguish an exception was thrown v.s. an error value was returned. It is an interesting issue.
First a quick review. As you know,
try [some code]
will evaluate the code and return the result. If an error occurs, it is thrown and caught by try, and the error value is returned.
You can write:
if error? err: try [some code] [handle err]
However, because in REBOL an error is a first class datatype. You are allowed to create, store, and return errors as actual values.
an-error: make error! "a simple error"
In R3, this does not cause an exception, it simple creates an error value. To force it as an exception:
But, in try, you now have an ambiguous evaluation case:
err: try [some code where an error exception happens]
err: try [make error! "some error"]
Both return an error value, but the first try had an actual exception, and the second did not. It simply returned an error value.
It has been suggested that we add a refinement to try that helps us to process the exception case:
value: try/except [some code] [handle the error]
However, that is not enough, the error handling block will often need to know the error value. This means the exception is actually a function:
value: try/except [some code] func [error] [handle the error]
When the exception occurs, the error handler function will be called, and that code will also provide the return value for the try.
Although this line seems a bit "wordy", it's the functional language way to do things like this.
It would be easy to create a mezzanine function to make the approach look more like switch:
value: try-except [some code] [
script zero-divide [handle this case]
script out-of-range [handle this case]
default [other cases]
This is done in many other languages, but it's just a wrapper, and may or may not be worthwhile as a standard function.