When antiform ERROR! first arrived, there needed to be a way to capture them.
I was uncomfortable having the LIFT operator blindly turn an antiform ERROR! into a quasi-ERROR!, because that could sweep things under the rug. You might have been LIFT-ing because you wanted to capture a PACK! (including VOID) or so you could put a NULL or SPLICE! into a BLOCK!. Why would you conflate that with error suppression?
So there was LIFT that didn't meta an ERROR! antiform, and LIFT* that would.
Now you want to capture an error from an operation. You've got a situation like:
result': lift* eval code
if error? unlift result' [
let warning: unquasi result'
; ... handle disarmed error (warning) ...
] else [
let result: unlift result'
; ... handle result ...
]
I thought this was a bit more painful than it needed to be, so I created ENTRAP.
result': entrap code
if warning? result' [
; ... handle disarmed error (warning) in result' ...
] else [
let result: unlift result'
; ... handle result ...
]
Not a heck of a lot better. But saved a bit of boilerplate.
Now We Can Do Better!
(^result: ...) will write the lifted representation of the evaluation into result, but still return the original result. So if the original result was an ERROR! it will still be an error out.
But you can suppress that. So look at this magic:
try ^result: eval code ; TRY suppresses, but meta-ERROR! still wrote to result
if error? ^result [
; ... handle error in ^result ...
] else [
; ... handle original result as ^result ...
]
![]()
So What, Then, Is TRAP Now?
Right now EVAL only lets you bubble out an error if it's the last step. Interstitial ERROR! will lead to a PANIC if there's no triage:
>> error? eval [print "step one" 1 / 0]
step one
== \~okay~\ ; antiform
>> error? eval [1 / 0 print "step two"]
!! PANIC: division by zero
That's kind of a non-negotiable default, because when you branch and pipe ERROR! values around you intend for the error to be the product of the last branch step, not some incidental code that ran before that last step.
So maybe TRAP is a construct that lets you bail early, getting an error from any step:
>> error? trap [print "step one" 1 / 0]
step one
== \~okay~\ ; antiform
>> error? trap [1 / 0 print "step two"]
== \~okay~\ ; antiform
Or maybe that's a refinement to EVAL. I dunno.
Another thing to point out is that ERROR! is not an exception (panic). It's a FAIL state that can be piped around. So using EXCEPT as name for the postfix error handler is a little off:
eval code except ^e -> [
; handle ERROR!
]
Should that be TRAP ?
eval code trap ^e -> [
; handle ERROR!
]
Food for thought. In any case, I'm really pleased to see how (^x: ...) vs. (try ^x: ...) offers the choices I was seeking, in so much cleaner a way.