With definitional errors, the landscape changes considerably for how we think about error handling.
In this world, there are not a lot of good reasons to use what we've been calling "TRAP". (historical Redbol's TRY)
By its design, TRAP will intercept any error in code at any depth. I've shown that when ATTEMPT was based on this, it was not good:
>> attempt [print "Attempting to read file" read %nonexistent-file.txt]
Attempting to read file
; null
>> attempt [print "Attempting but made typos" rread %nonexistent-file.txt]
; null
That's fixed now, because ATTEMPT is based on REDUCE-EACH with a ^META variable.
But back to TRAP. The problem isn't just about typos. It's about the illusion that there's something you can do to react to an arbitrary error...when the constructs you were using didn't even understand it well enough to pipe it through to their output.
In almost all cases, a "TRAP"'d error cannot be reacted to sanely...it has to be reported.
It's for this reason that languages like Rust pretty much enforce a panic
And our case is even more compelling. For example: How many places is it ever a good idea to sweep a typo under the rug, and just run some other code?
The few cases it's legitimate are things like the console...where you trap the error and present it, so the user knows it happens and can do something about it. This sort of thing is nearly the only legitimate usage of TRAP.
Might We Make It Look More "Special" To Discourage Use?
I thought at minimum we should move it to a place that shows it's more of a "system utility" than a "language feature".
So calling it SYS.UTIL.TRAP
would be a step in that direction.
And as long as we're discouraging use of this, it seems a bit of a waste to take such a short name. It could be SYS.UTIL.TRAP-ANY-ERROR
or similar, and then TRAP could be used for something should be used more often.
(It could act like ATTEMPT, but evaluate to the error as its primary result instead of the body of the block.)
Things to think about. Anyway, I've made some progress on definitional errors in the scanner and with TO and MAKE operations, so some of the things people like to trap (like conversions) should work correctly with attempt now.
For instance, in this finite-integer world... an out of range error:
>> attempt [to integer! "10483143873258978444434343"]
; null
>> attempt [to intgeer! "10483143873258978444434343"]
** Script Error: intgeer! word is attached to a context, but unassigned
>> to integer! "10483143873258978444434343" except e -> [print ["Error:" mold e]]
Error: make error! [
type: 'Script
id: 'bad-make-arg
message: ["cannot MAKE/TO" :arg1 "from:" :arg2]
near: [to integer! "10483143873258978444434343" ** except e -> ***]
where: [to args]
file: '
line: 1
arg1: #[datatype! integer!]
arg2: "10483143873258978444434343"
]
Should be a more specific error, now that I look at that. But I guess it just wasn't.