Page 1 of 2
Error Trapping
Posted: Mon Jun 08, 2015 4:01 pm
by paulmansour
So every 5 years or so, I have to do some error trapping. It is always deja vu all over again. I am surprised when the error guard 0:: does not catch errors farther down the stack. I then remember the scoping rules.
Anyway, here is the question: what are the various techniques for global error trapping of a dfn? I can think of two useful solutions.
1. Make sure all the sub dfns are defined within the top level dfn, then 0:: will catch everything.
2. Write a traditional operator to call the dfn, something like:
z←x(f Try)y
⍝ Try function f on y.
:Trap 0
z←f y
:Else
Signal an error here with message x, or return something, etc.
:EndTrap
Any other techniques worth noting?
Re: Error Trapping
Posted: Tue Jun 09, 2015 9:51 am
by JohnS|Dyalog
Hi Paul,
The only other technique that springs to mind is to catch and ⎕signal at each capsule (outermost dfn) level.
{
0::⎕signal ⎕en ⍝ pass un-trapped error back to caller.
...
I appreciate this adds a fair amount of clutter, particularly for small capsules.
We are strongly considering changing error guards to have dynamic, rather than lexical scope, so that the following would work:
main←{0::'Eh?' ⋄ sub ⍵}
sub←{÷⍵}
main 0
Eh?
How would people feel about this? Would this change break anyone's code?
John.
Re: Error Trapping
Posted: Tue Jun 09, 2015 10:48 am
by Phil Last
Acre's technique is merely a slight enhancement of John's whereby the zero is replaced by a call to function Error (say) and the - ⎕SIGNAL ⎕EN is replaced by function Signal (say) so each "capsule" is headed by:
[1] Error''::Signal''
Error may be defined such that it returns either zilde or zero depending on whether a globally accessible debug setting is set on or off:
Error←{settings.debug↓0}
Signal may be derived as:
Signal←⎕SIGNAL/∘{⌽⎕EN,⎕DM}
Using the first item of ⎕DM wherever it is called allows it to pass on a bespoke error message.
Re: Error Trapping
Posted: Tue Jun 09, 2015 10:55 am
by Phil Last
JohnS wrote:How would people feel about this? Would this change break anyone's code?
Would this change break anyone's code? wouldn't be surprised either way because after eighteen years of lexical I find dynamic scope quite counter-intuitive and the interaction between the two almost inexplicable.
How would people feel about this? a backward step?
Re: Error Trapping
Posted: Tue Jun 09, 2015 11:52 am
by JohnS|Dyalog
I should have been more specific. The proposal is to maintain lexical scope for error guards within a capsule, which is a requirement of tail-call optimisation, but to allow the guard to leak across only capsule-to-capsule calls. Where a "capsule" is the outermost dfn, which may contain any number of inner nested dfns.
The proposed behaviour should affect only an error that is currently un-trapped. We feel that error-trapping is special and unlike other scope scenarios and (some of us quite strongly) that the current behaviour is broken.
Rest assured, we wouldn't make this change without a strong consensus that it's the right way to go.
Rest assured also that this is not the slippery slope for lexical scoping, which IMHO is a wonderful thing.
John
Re: Error Trapping
Posted: Tue Jun 09, 2015 1:26 pm
by paulmansour
John,
Thanks for the response. I think the change is a good idea, but I would not be comfortable with the change unless Phil and most if not all the top dfnistas were sold on it. It would certainly remove the need for the periodic head scratching that I engage in.
Can I take it that you are using more than the royal "we" here:
We feel that error-trapping is special and unlike other scope scenarios and (some of us quite strongly) that the current behaviour is broken.
and that you are not acting under pressure from scheming court advisers? ;)
I assume you are for this change?
Paul
Re: Error Trapping
Posted: Tue Jun 09, 2015 7:21 pm
by JohnS|Dyalog
:-) There's no arm-twisting.
I think this is a good idea, so long as the change is restricted to error-guards on capsule-to-capsule calls. I suppose this could break existing code by inserting a new error-guard between the called function and a global catch-all.
If we're worried about this, perhaps we should investigate a new, distinct dynamic error-guard mechanism. How about three colons?
{0:::'Eh?' ⋄ foo ⍵} ⍝ Dynamic error guard active within called fn foo.
Re: Error Trapping
Posted: Tue Jun 09, 2015 10:03 pm
by Phil Last
Maybe it's the global catch-all or the similarity to it that dynamic scope presents that worries me. Sometimes you just want your code to stop at the error without having to worry whether some unknown process is going to intervene that just happens to be somewhere further up the stack.
When each subsystem has its own protocol you really don't want one interfering with another.
I guess so long as it's totally predictable exactly how ALL the different mechanisms: ⎕TRAP, :Trap, :: interact and what has priority at different levels when each has its own selection of error codes it should be OK.
Re: Error Trapping
Posted: Wed Jun 10, 2015 7:27 am
by kai
Having battled with error trapping on what I call "a general level" a lot I can only express my strong support for a change here.
I am particularly happy with the three-colon-solution. It's easily distinguishable from ordinary error guards and it would not break anything I guess. Excellent.
Re: Error Trapping
Posted: Mon Apr 11, 2016 11:39 am
by paulmansour
Further thoughts on error guards and dynamic scope.
One of the pitfalls of ⎕Trap is that trapping all errors can lead to an infinite loop with an error in the error handling code.
The keyword :Trap avoids this.
If dfn error guards were changed to be dynamically scoped, then they would behave like :Trap, is that correct? That is, this:
{
0::HandleAnyError 0
RunMainProgram 0
}
would be essentially the same as this:
:Trap 0
RunMainProgram 0
:Else
HandleAnyError 0
:EndTrap
I think I would vote to have the behavior of error guards changed.