Difference between revisions of "Error Trapping with $ETRAP"

From VistApedia
Jump to: navigation, search
m
(Formatting and typos)
 
Line 14: Line 14:
 
Jawad  
 
Jawad  
  
Subject: Exception handeling in Mumps
+
Subject: Exception handling in Mumps
  
Exception handeling can be performed in any modern prgramming language, i
+
Exception handling can be performed in any modern programming language, I
was wondering if there is any kind of exception handeling in Mumps.
+
was wondering if there is any kind of exception handling in Mumps.
Mian goal is to avoid code crash. i dont think there are any "try" "Catch"
+
Main goal is to avoid code crash. I don't think there are any "try" "Catch"
 
blocks in Mumps.  I would like to know any approach that mumps programmers
 
blocks in Mumps.  I would like to know any approach that mumps programmers
 
use to avoid code crash.
 
use to avoid code crash.
Line 35: Line 35:
 
   N $ET,$ES  
 
   N $ET,$ES  
 
   S $ET="HNDLR^MYRTN" ;do risky stuff  
 
   S $ET="HNDLR^MYRTN" ;do risky stuff  
  HNDLR ;  
+
HNDLR ;  
 
   ;your own logic here  
 
   ;your own logic here  
 
   D ^%ZTER ;if you want to log the error  
 
   D ^%ZTER ;if you want to log the error  
Line 47: Line 47:
 
kdtop
 
kdtop
  
Greg, can you educate me a bit more about UNWIND.  You say it "unwinds" the error stack and quits back to the calling routine.  Does this mean that you don't really nead a QUIT on the line after it? Does it go back to the same line that caused the error, or the next line after?  
+
Greg, can you educate me a bit more about UNWIND.  You say it "unwinds" the error stack and quits back to the calling routine.  Does this mean that you don't really need a QUIT on the line after it? Does it go back to the same line that caused the error, or the next line after?  
 
Thanks Kevin
 
Thanks Kevin
  
Line 60: Line 60:
  
 
   UNWIND  ;Unwind stack for new error trap. Called by app code.
 
   UNWIND  ;Unwind stack for new error trap. Called by app code.
           S $ECODE="" S $ETRAP="D UNW^%ZTER Q:'$QUIT  Q -9" S
+
           S $ECODE="" S $ETRAP="D UNW^%ZTER Q:'$QUIT  Q -9" S $ECODE=",U1,"
  $ECODE=",U1,"
 
 
   UNW      Q:$ESTACK>1  S $ECODE="" Q
 
   UNW      Q:$ESTACK>1  S $ECODE="" Q
  
Line 69: Line 68:
 
to "D UNW^%ZTER Q:'$QUIT  Q -9" and set the error code to ",U1,".  
 
to "D UNW^%ZTER Q:'$QUIT  Q -9" and set the error code to ",U1,".  
  
Okay, so what does THAT mean? Let's take it a piece at a time. Ther first step
+
Okay, so what does THAT mean? Let's take it a piece at a time. The first step
 
in handling any error will be to call UNW^%ZTER, then just QUIT if the
 
in handling any error will be to call UNW^%ZTER, then just QUIT if the
 
code was not invoked as a function, or QUIT with the value -9 (if it
 
code was not invoked as a function, or QUIT with the value -9 (if it
Line 107: Line 106:
 
Right, I'm confused already.
 
Right, I'm confused already.
  
   >Let's take it a piece at a time. Ther first step
+
   > Let's take it a piece at a time. The first step
 
   > in handling any error will be to call UNW^%ZTER, then just QUIT if the
 
   > in handling any error will be to call UNW^%ZTER, then just QUIT if the
 
   > code was not invoked as a function, or QUIT with the value -9 (if it
 
   > code was not invoked as a function, or QUIT with the value -9 (if it
Line 131: Line 130:
 
I have seen documentation of the error codes...
 
I have seen documentation of the error codes...
  
   >The last piece of
+
   > The last piece of
 
   > the puzzle is to look at UNW^%ZTER. The code here is just Q:$ESTACK>1  S
 
   > the puzzle is to look at UNW^%ZTER. The code here is just Q:$ESTACK>1  S
 
   > $ECODE="" Q. That simply looks at $ESTACK, and if it's greater than 1
 
   > $ECODE="" Q. That simply looks at $ESTACK, and if it's greater than 1
Line 160: Line 159:
 
So in your example below:
 
So in your example below:
  
   1>N $ET,$ES
+
   1> N $ET,$ES
   2> S $ET="HNDLR^MYRTN"
+
   2> S $ET="HNDLR^MYRTN"
   3> ;do risky stuff
+
   3> ;do risky stuff
 
   4> HNDLR ;
 
   4> HNDLR ;
   5> ;your own logic here
+
   5> ;your own logic here
   6> D ^%ZTER ;if you want to log the error
+
   6> D ^%ZTER ;if you want to log the error
   7> D UNWIND^%ZTER
+
   7> D UNWIND^%ZTER
   8> Q
+
   8> Q
  
 
"the calling routine" would be where?  I would say that UNWIND^%ZTER
 
"the calling routine" would be where?  I would say that UNWIND^%ZTER
Line 174: Line 173:
 
back somewhere around line 3 ("risky stuff")
 
back somewhere around line 3 ("risky stuff")
  
   >If you want to go back to where you left off when the error occured, you need
+
   > If you want to go back to where you left off when the error occurred, you
   > to write your code differently, but I recommend placing any code likely
+
   > need to write your code differently, but I recommend placing any code likely
 
   > to raise an error in a DO block by itself.
 
   > to raise an error in a DO block by itself.
  
Line 189: Line 188:
 
   ...
 
   ...
  
Right, I'm confused already.
+
Right, I'm confused already.
  
 
[Greg]
 
[Greg]
 
My experience is that everyone finds it confusing.
 
My experience is that everyone finds it confusing.
  
> Let's take it a piece at a time. Ther first step in handling any error will be to call UNW^%ZTER, then just QUIT if the code was not invoked as a function, or QUIT with the value -9 (if it was).
+
> Let's take it a piece at a time. The first step in handling any error will
 +
> be to call UNW^%ZTER, then just QUIT if the code was not invoked as a  
 +
> function, or QUIT with the value -9 (if it was).
  
If an error was encountered, and the user trapped it (as in your
+
If an error was encountered, and the user trapped it (as in your
original example), and then called UNWIND^%ZTER, then I don't see what
+
original example), and then called UNWIND^%ZTER, then I don't see what
setting $ETRAP does to handle the current problem.  It seems only that
+
setting $ETRAP does to handle the current problem.  It seems only that
is will redirect the error handler for NEXT time.  Furthermore, we have
+
is will redirect the error handler for NEXT time.  Furthermore, we have
set $ECODE="" initially, clearing the error state.
+
set $ECODE="" initially, clearing the error state.
  
Let's see, after changing $ECODE to UNWIND^%ZTER, it sets another error
+
Let's see, after changing $ECODE to UNWIND^%ZTER, it sets another error
state and then quits.  Will this cause the $ECODE to be executed a
+
state and then quits.  Will this cause the $ECODE to be executed a
SECOND time?  This time launching UNW^%ZTER??
+
SECOND time?  This time launching UNW^%ZTER??
  
 
[Greg]
 
[Greg]
That's right. The current error is  cleared (S $ECODE=""), but there
+
That's right. The current error is  cleared (S $ECODE=""), but
 
errors are stacked, and there may be multiple outstanding errors. That
 
errors are stacked, and there may be multiple outstanding errors. That
way, if thee are further errors, they will be handled by UNW^%ZTER.
+
way, if there are further errors, they will be handled by UNW^%ZTER.
  
>After resetting the error trap, set the error code to ",U1,". To  make
+
>After resetting the error trap, set the error code to ",U1,". To  make
>sense of that, you need to know that errors are either part of the   
+
>sense of that, you need to know that errors are either part of the   
>MUMPS standard and begin with M (e.g., M13), are vendor specific and   
+
>MUMPS standard and begin with M (e.g., M13), are vendor specific and   
>begin with Z, or user defined and begin with U. The list of errors is   
+
>begin with Z, or user defined and begin with U. The list of errors is   
>always comma delimited, hence ",U1," (Hmm...so I guess this means the   
+
>always comma delimited, hence ",U1," (Hmm...so I guess this means the   
>SAC needs to prohibit use of U1.) We're almost there.
+
>SAC needs to prohibit use of U1.) We're almost there.
  
I have seen documentation of the error codes...
+
I have seen documentation of the error codes...
  
>The last piece of
+
> The last piece of
> the puzzle is to look at UNW^%ZTER. The code here is just Q:$ESTACK>1
+
> the puzzle is to look at UNW^%ZTER. The code here is just  
 +
> Q:$ESTACK>1 S  $ECODE="" Q.
 +
> That simply looks at $ESTACK, and if it's greater than 1 
 +
> (there is more than one error in the error stack), it QUITs,
 +
> effectively  popping the stack. Finally, it clears the error condition
 +
> with S  $ECODE="" and QUITs.
  
>S $ECODE="" Q. That simply looks at $ESTACK, and if it's greater than
+
  Well, it doesn't seem to be able to remove more than one level of error
>1 (there is more than one error in the error stack), it QUITs,
+
  code.  I don't know if there would ever be a situation where more than
>effectively popping the stack. Finally, it clears the error condition
+
  that would be needed. But the term "unwind" implies to me "back up as
>with S $ECODE="" and QUITs.
+
  far as needed" instead of just "pop 1 level back"
  
Well, it doesn't seem to be able to remove more than one level of error
+
If $ESTACK>1 the error handler will quit, popping an error off the
code. I don't know if there would ever be a situation where more than
+
  stack, but if there are outstanding unhandled errors, it may be invoked
that would be needed. But the term "unwind" implies to me "back up as
+
again. The idea is to allow this new error handler to consume the stack.
far as needed" instead of just "pop 1 level back"
 
  
If $ESTACK>1 the error handler will quit, popping an error off the
+
> Okay, so how do you translate that into something more human friendly?
stack, but if there are outstanding unhandled errors, it may be invoked
+
> At the most basic level, it's just popping off any errors that might
again. The idea is to allow this new error handler to consume the stack.
+
> be left on the stack (without handling them), and clearing the error
 +
> condition.
  
> Okay, so how do you translate that into something more human friendly?
+
I had thought that there was some error logging here somehow, but I
> At the most basic level, it's just popping off any errors that might
+
don't see in this part of the code...
> be left on the stack (without handling them), and clearing the error
 
> condition.
 
 
 
I had thought that there was some error logging here somehow, but I
 
don't see in this part of the code...
 
  
 
[Greg]
 
[Greg]
 
This code does not log the error. In order to log an error D ^%ZTER
 
This code does not log the error. In order to log an error D ^%ZTER
(different entry point. In most cases, you will make the two calls one
+
(different entry point). In most cases, you will make the two calls one
 
after another, i.e.,
 
after another, i.e.,
  
D ^%ZTER ;log the error
+
* D ^%ZTER ;log the error
D UNWIND^%ZTER ;unwind the stack (so you can continue with a clean
+
* D UNWIND^%ZTER ;unwind the stack (so you can continue with a clean slate)
slate)
 
  
> In response to your other question: No, you don't need a QUIT, but it
+
> In response to your other question: No, you don't need a QUIT, but it
> doesn't hurt either. I tend to put a QUIT at the end of each section
+
> doesn't hurt either. I tend to put a QUIT at the end of each section
> of code to prevent unintentional "fall through" errors, and when code
+
> of code to prevent unintentional "fall through" errors, and when code
> is meant to fall through, I say so in a comment.
+
> is meant to fall through, I say so in a comment.When you call UNWIND^%ZTER
 +
> control returns to the calling routine, not where you left off.
  
When you call UNWIND^%ZTER
+
So in your example below:
> control returns to the calling routine, not where you left off.
 
  
So in your example below:
+
1>  N $ET,$ES
 +
2>  S $ET="HNDLR^MYRTN"
 +
3>  ;do risky stuff
 +
4> HNDLR ;
 +
5>  ;your own logic here
 +
6>  D ^%ZTER ;if you want to log the error
 +
7>  D UNWIND^%ZTER
 +
8>  Q
  
1>N $ET,$ES
+
"the calling routine" would be where?  I would say that UNWIND^%ZTER
2> S $ET="HNDLR^MYRTN"
+
would quit back to the line after it was called, namely line 8.  In
3> ;do risky stuff
+
which case the Q would be needed.  And the Q in line 8 would then jump
4> HNDLR ;
+
back somewhere around line 3 ("risky stuff")
5> ;your own logic here
 
6> D ^%ZTER ;if you want to log the error
 
7> D UNWIND^%ZTER
 
8> Q
 
 
 
"the calling routine" would be where?  I would say that UNWIND^%ZTER
 
would quit back to the line after it was called, namely line 8.  In
 
which case the Q would be needed.  And the Q in line 8 would then jump
 
back somewhere around line 3 ("risky stuff")
 
  
 
[Greg]
 
[Greg]
 
No, line 7 is part of the error handler. I mean control will be
 
No, line 7 is part of the error handler. I mean control will be
transferred back to the block of code that invoked the copde causing the
+
transferred back to the block of code that invoked the code causing the
 
error to be generated.
 
error to be generated.
  
>If you
+
>If you
> want to go back to where you left off when the error occured, you need
+
> want to go back to where you left off when the error occurred, you need
>to write your code differently, but I recommend placing any code likely
+
>to write your code differently, but I recommend placing any code likely
>to raise an error in a DO block by itself.
+
>to raise an error in a DO block by itself.
  
I will say that I was pleased to learn about $QUIT.  I hadn't
+
I will say that I was pleased to learn about $QUIT.  I hadn't
encountered that before.  I looked it up and understand it now.  I have
+
encountered that before.  I looked it up and understand it now.  I have
had times where I could have used that... :-)
+
had times where I could have used that... :-)
  
 
[Greg]
 
[Greg]
Line 296: Line 294:
 
subject to change.
 
subject to change.
  
Thanks
+
Thanks
Kevin
+
Kevin

Latest revision as of 18:46, 6 April 2010

Here is a thread regarding $ETRAP

Here is a quick and dirty solution:

 do
 . new $etrap set $etrap="write ""(Invalid M Code!.  Error Trapped.)"",! set $etrap="""",$ecode="""""
 . do SomeThingRisky

Kevin


Exception handling in Mumps

 -----------------------------------			

Jawad

Subject: Exception handling in Mumps

Exception handling can be performed in any modern programming language, I was wondering if there is any kind of exception handling in Mumps. Main goal is to avoid code crash. I don't think there are any "try" "Catch" blocks in Mumps. I would like to know any approach that mumps programmers use to avoid code crash.

Jawad

 -----------------------------------			

Gregory Woodhouse

Yes. It's called error trapping in MUMPS. The basic pattern is to NEW $ETRAP and $ESTACK and set $ETRAP to the code reference for your handler. Control will be transferred there if an error is raised by setting $ECODE, or if an error occurs during execution. The value of $ECODE will be the error code or codes. You need to be sure to clear the error if you want execution to continue.

You can clear a single error by setting $ECODE to "", but Kernel provides a utility to unwind the error stack and quit back to the calling routine, D UNWIND^ %ZTER. To log an error simply D ^%ZTER.

So, your code may look something like this

 N $ET,$ES 
 S $ET="HNDLR^MYRTN" ;do risky stuff 
HNDLR ; 
 ;your own logic here 
 D ^%ZTER ;if you want to log the error 
 D UNWIND^%ZTER 
 Q 

Gregory Woodhouse

 -----------------------------------			

kdtop

Greg, can you educate me a bit more about UNWIND. You say it "unwinds" the error stack and quits back to the calling routine. Does this mean that you don't really need a QUIT on the line after it? Does it go back to the same line that caused the error, or the next line after? Thanks Kevin

 -----------------------------------			

Woodhouse, Gregory J.

I always put QUIT at the end of my code. Call it a bad habit.

Anyway, I've never found a very clear explanation in the documentation of what UNWIND^%ZTER does. Let's look at the code:

 UNWIND   ;Unwind stack for new error trap. Called by app code.
          S $ECODE="" S $ETRAP="D UNW^%ZTER Q:'$QUIT  Q -9" S $ECODE=",U1,"
 UNW      Q:$ESTACK>1  S $ECODE="" Q

This can be paraphrased as follows:

First, clear the current error (S $ECODE="") and set the error handler to "D UNW^%ZTER Q:'$QUIT Q -9" and set the error code to ",U1,".

Okay, so what does THAT mean? Let's take it a piece at a time. The first step in handling any error will be to call UNW^%ZTER, then just QUIT if the code was not invoked as a function, or QUIT with the value -9 (if it was). After resetting the error trap, set the error code to ",U1,". To make sense of that, you need to know that errors are either part of the MUMPS standard and begin with M (e.g., M13), are vendor specific and begin with Z, or user defined and begin with U. The list of errors is always comma delimited, hence ",U1," (Hmm...so I guess this means the SAC needs to prohibit use of U1.) We're almost there. The last piece of the puzzle is to look at UNW^%ZTER. The code here is just Q:$ESTACK>1 S $ECODE="" Q. That simply looks at $ESTACK, and if it's greater than 1 (there is more than one error in the error stack), it QUITs, effectively popping the stack. Finally, it clears the error condition with S $ECODE="" and QUITs.

Okay, so how do you translate that into something more human friendly? At the most basic level, it's just popping off any errors that might be left on the stack (without handling them), and clearing the error condition.

In response to your other question: No, you don't need a QUIT, but it doesn't hurt either. I tend to put a QUIT at the end of each section of code to prevent unintentional "fall through" errors, and when code is meant to fall through, I say so in a comment. When you call UNWIND^%ZTER control returns to the calling routine, not where you left off. If you want to go back to where you left off when the error occured, you need to write your code differently, but I recommend placing any code likely to raise an error in a DO block by itself.

 -----------------------------------			


kdtop

...

Right, I'm confused already.

 > Let's take it a piece at a time. The first step
 > in handling any error will be to call UNW^%ZTER, then just QUIT if the
 > code was not invoked as a function, or QUIT with the value -9 (if it
 > was).

If an error was encountered, and the user trapped it (as in your original example), and then called UNWIND^%ZTER, then I don't see what setting $ETRAP does to handle the current problem. It seems only that is will redirect the error handler for NEXT time. Furthermore, we have set $ECODE="" initially, clearing the error state.

Let's see, after changing $ECODE to UNWIND^%ZTER, it sets another error state and then quits. Will this cause the $ECODE to be executed a SECOND time? This time launching UNW^%ZTER??

 > After resetting the error trap, set the error code to ",U1,". To
 > make sense of that, you need to know that errors are either part of the
 > MUMPS standard and begin with M (e.g., M13), are vendor specific and
 > begin with Z, or user defined and begin with U. The list of errors is
 > always comma delimited, hence ",U1," (Hmm...so I guess this means the
 > SAC needs to prohibit use of U1.) We're almost there.

I have seen documentation of the error codes...

 > The last piece of
 > the puzzle is to look at UNW^%ZTER. The code here is just Q:$ESTACK>1  S
 > $ECODE="" Q. That simply looks at $ESTACK, and if it's greater than 1
 > (there is more than one error in the error stack), it QUITs, effectively
 > popping the stack. Finally, it clears the error condition with S
 > $ECODE="" and QUITs.

Well, it doesn't seem to be able to remove more than one level of error code. I don't know if there would ever be a situation where more than that would be needed. But the term "unwind" implies to me "back up as far as needed" instead of just "pop 1 level back"

 > Okay, so how do you translate that into something more human friendly?
 > At the most basic level, it's just popping off any errors that might be
 > left on the stack (without handling them), and clearing the error
 > condition.

I had thought that there was some error logging here somehow, but I don't see in this part of the code...

 > In response to your other question: No, you don't need a QUIT, but it
 > doesn't hurt either. I tend to put a QUIT at the end of each section of
 > code to prevent unintentional "fall through" errors, and when code is
 > meant to fall through, I say so in a comment.
 >When you call UNWIND^%ZTER control returns to the calling routine, not where you left off.

So in your example below:

 1>  N $ET,$ES
 2>  S $ET="HNDLR^MYRTN"
 3>  ;do risky stuff
 4> HNDLR ;
 5>  ;your own logic here
 6>  D ^%ZTER ;if you want to log the error
 7>  D UNWIND^%ZTER
 8>  Q

"the calling routine" would be where? I would say that UNWIND^%ZTER would quit back to the line after it was called, namely line 8. In which case the Q would be needed. And the Q in line 8 would then jump back somewhere around line 3 ("risky stuff")

 > If you want to go back to where you left off when the error occurred, you
 > need to write your code differently, but I recommend placing any code likely
 > to raise an error in a DO block by itself.

I will say that I was pleased to learn about $QUIT. I hadn't encountered that before. I looked it up and understand it now. I have had times where I could have used that... :-)

Thanks Kevin

 -----------------------------------			
 ...
Right, I'm confused already.

[Greg] My experience is that everyone finds it confusing.

> Let's take it a piece at a time. The first step in handling any error will
> be to call UNW^%ZTER, then just QUIT if the code was not invoked as a 
> function, or QUIT with the value -9 (if it was).
If an error was encountered, and the user trapped it (as in your
original example), and then called UNWIND^%ZTER, then I don't see what
setting $ETRAP does to handle the current problem.  It seems only that
is will redirect the error handler for NEXT time.  Furthermore, we have
set $ECODE="" initially, clearing the error state.
Let's see, after changing $ECODE to UNWIND^%ZTER, it sets another error
state and then quits.  Will this cause the $ECODE to be executed a
SECOND time?  This time launching UNW^%ZTER??

[Greg] That's right. The current error is cleared (S $ECODE=""), but errors are stacked, and there may be multiple outstanding errors. That way, if there are further errors, they will be handled by UNW^%ZTER.

>After resetting the error trap, set the error code to ",U1,". To  make
>sense of that, you need to know that errors are either part of the  
>MUMPS standard and begin with M (e.g., M13), are vendor specific and  
>begin with Z, or user defined and begin with U. The list of errors is  
>always comma delimited, hence ",U1," (Hmm...so I guess this means the  
>SAC needs to prohibit use of U1.) We're almost there.
I have seen documentation of the error codes...
> The last piece of
> the puzzle is to look at UNW^%ZTER. The code here is just 
> Q:$ESTACK>1 S  $ECODE="" Q. 
> That simply looks at $ESTACK, and if it's greater than 1  
> (there is more than one error in the error stack), it QUITs,
> effectively  popping the stack. Finally, it clears the error condition
> with S  $ECODE="" and QUITs.
Well, it doesn't seem to be able to remove more than one level of error
code.  I don't know if there would ever be a situation where more than
that would be needed.  But the term "unwind" implies to me "back up as
far as needed" instead of just "pop 1 level back"
If $ESTACK>1 the error handler will quit, popping an error off the
stack, but if there are outstanding unhandled errors, it may be invoked
again. The idea is to allow this new error handler to consume the stack.
> Okay, so how do you translate that into something more human friendly?
> At the most basic level, it's just popping off any errors that might
> be left on the stack (without handling them), and clearing the error
> condition.
I had thought that there was some error logging here somehow, but I
don't see in this part of the code...

[Greg] This code does not log the error. In order to log an error D ^%ZTER (different entry point). In most cases, you will make the two calls one after another, i.e.,

  • D ^%ZTER ;log the error
  • D UNWIND^%ZTER ;unwind the stack (so you can continue with a clean slate)
> In response to your other question: No, you don't need a QUIT, but it
> doesn't hurt either. I tend to put a QUIT at the end of each section
> of code to prevent unintentional "fall through" errors, and when code
> is meant to fall through, I say so in a comment.When you call UNWIND^%ZTER
> control returns to the calling routine, not where you left off.
So in your example below:
1>  N $ET,$ES
2>  S $ET="HNDLR^MYRTN"
3>  ;do risky stuff
4> HNDLR ;
5>  ;your own logic here
6>  D ^%ZTER ;if you want to log the error
7>  D UNWIND^%ZTER
8>  Q
"the calling routine" would be where?  I would say that UNWIND^%ZTER
would quit back to the line after it was called, namely line 8.  In
which case the Q would be needed.  And the Q in line 8 would then jump
back somewhere around line 3 ("risky stuff")

[Greg] No, line 7 is part of the error handler. I mean control will be transferred back to the block of code that invoked the code causing the error to be generated.

>If you
> want to go back to where you left off when the error occurred, you need
>to write your code differently, but I recommend placing any code likely
>to raise an error in a DO block by itself.
I will say that I was pleased to learn about $QUIT.  I hadn't
encountered that before.  I looked it up and understand it now.  I have
had times where I could have used that... :-)

[Greg] Unfortunately, it is not currently allowed by the SAC, but that is subject to change.

Thanks
Kevin