I'm a bit confused over error handling in Rebol. It has THROW and CATCH constructions:
>> repeat x 10 [if x = 9 [throw "Nine!"]]
** Throw error: no catch for throw: make error! 2
>> catch [repeat x 10 [if x = 9 [throw "Nine!"]]]
== "Nine!"
But this throwing and catching is unrelated to the handler passed to the /EXCEPT refinement on TRY:
>> try/except [throw "Nine!"] [print "Exception handled!"]
** Throw error: no catch for throw: make error! 2
That's very specific to Rebol's error type:
>> try/except [print 1 / 0] [print "Error handled!"]
Error handled!
If you want you can trigger your own errors, but not using THROW as you would in other languages. Throwing errors will just lead to a complaint about not being caught, as any other value type:
>> try/except [throw make error! "Error string"] [print "Error handled!"]
** Throw error: no catch for throw: make error! 2
You must DO them to get the evaluator to try and execute something of type error! to cause what it considers an "exception":
>> try/except [do make error! "Error string"] [print "Error handled!"]
Error handled!
(Note: You can use pre-made errors apparently such as cause-error 'Script 'invalid-type function!
-- see system/catalog/errors
for more.)
Leaving off the /EXCEPT refinement will let you receive any errors as a value. However, that seems to make it impossible to distinguish between whether the error was invoked or not:
>> probe try [do make error! "Some error"]
make error! [
code: 800
type: 'User
id: 'message
arg1: "some error"
arg2: none
arg3: none
near: none
where: none
]
** User error: "Some error"
>> probe try [make error! "Some error"]
make error! [
code: 800
type: 'User
id: 'message
arg1: "Some error"
arg2: none
arg3: none
near: none
where: none
]
** User error: "Some error"
It would seem that CATCH has a similar lack of distinction between returning a value and having a value thrown. But there's a tool to get around that with "named throws":
>> code: [repeat x 10 [if x = 9 [throw/name "Nine!" 'number]]]
>> catch/name [do code] 'number
== "Nine!"
>> catch/name [do code] 'somethingelse
** Throw error: no catch for throw: make error! 2
So now for the questions:
Is there a practical value to this separation? How does one decide whether to use THROW and CATCH or a DO of an error and handle it with TRY/EXCEPT?
Does this distinction have precedent in other languages, and would /EXCEPT be better named /ON-ERROR or something?
Why does it say
"no catch for throw: make error! 2"
instead of something more informative? What is themake error! 2
?