TRY was changed from a "blank-in, null-out" meaning to use definitional errors. This allowed NULL to be both the input and the output...without risking inadvertently trapping errors from arbitrary depths. You'll really be intercepting the error emitted by the function just called:
>> first null ** Error: FIRST on NULL requires use of TRY >> try first null ; null
I mentioned something, which was that a "You need a TRY" ERROR! was actually able to carry a payload, saying what the TRY'd outcome value should be. (The only rule would be that a function emitting such an error should not have any side effects if it emits one of these errors.)
If we embrace this, it could really open the doors to what TRY means. Various constructs could offer meanings for what the TRY actually does:
>> unquote first ['abc] == abc >> unquote first [def] ** Error: Can't Unquote Plain WORD!, use TRY if Intentional >> try unquote first [def] == def
I'm sort of leaning to believing that this more general meaning of TRY may be much more interesting than the "null propagating" sense. There's kind of an explosion of potential for the "couldn't do what you asked me to do, but if that's what you meant..." outcomes.
At one point I suggested it would be nice to be able to have a COLLECT that didn't actually KEEP anything return NULL, so it could be ELSE-reactive. That meant if you really wanted an empty block, you'd have to do something like
any [collect [...], copy ] which was ugly. But the error could hold a freshly-copied block to be the result of a TRY:
>> collect [keep if false [<not kept>]] ** Error: COLLECT didn't KEEP anything, use TRY if intended >> try collect [keep if false [<not kept>]] == 
There are various technical reasons why ELSE can't be reactive to TRY-style errors. One fairly important one would be that if you used ELSE with a branching construct, it wouldn't be able to tell the difference between a branch that had a TRY-error and no branch taken:
>> case [true [unquote first [def]]] else [print "Took branch, runs due to UNQUOTE"] Took branch, runs due to UNQUOTE ; this would be bad
But... maybe the trick could be that if you pass ELSE a function that takes an argument, it assumes that means you handle TRY-style errors? (Because otherwise it could only be void/null... why take an arg?)
>> (unquote first [def]) else arg -> [print ["TRY error" arg]] TRY error def
It's a weird thought. Anyway, just wanted to write up the TRY concept...