The NetRexx Tutorial
- Process Control and Exceptions
NetRexx Tutorial - Process Control and Exceptions


Process Control and Exceptions

Introduction

In this chapter we will analyse how to better control the program flow of a NetRexx application.

Basic Concepts

Exception

The exception is a mechanism that allows you to (eventually) change the flow of control whenever some important or unexpected event (usually an error) occurs in your program. You then can try to cope with the problem (usually alerting the user that the problem has occurred), and avoid major disasters (usually exiting the program).

Exception Handling

Although NetRexx allows you to ignore (even explicitly) an exception, it is always a good idea to handle it, especially in the debugging phase of a program.

Exceptions in real life.

One way to happily generate exceptions, is to avoid any checking of input data. Not performing any validation on input data is REALLY a bad programming. In this case we'll avoid the checking on purpose, just to see what can happen.

Look at the following code:

 
+----------------------------------------------------------------------+
| -- expp1.nrx                                                         |01
| -- WARNING: this is bad programming: no checks on input              |02
| --          data are performed                                       |03
| --                                                                   |04
| parse arg n                                                          |05
| inv = 1/n                                                            |06
| say 'Inverse is:' inv                                                |07
| exit 0                                                               |08
+----------------------------------------------------------------------+
                                                               expp1.nrx
Download the source for the expp1.nrx example

This is definitely a bad code since:

So let's the fun begin and try to run some examples:

 
........................................................
-- this is OK
sp069.marchesi ~/src/java/Java/bin [0:18] java expp1 1
Inverse is: 1

-- this is divide by 0
sp069.marchesi ~/src/java/Java/bin [0:19] java expp1 0
netrexx.lang.DivideException: Divide by 0
        at netrexx.lang.Rexx.dodivide(Rexx.nrx:1648)
        at netrexx.lang.Rexx.OpDiv(Rexx.nrx:1557)
        at expp1.main(expp1.nrx:6)

-- non numeric input
sp069.marchesi ~/src/java/Java/bin [0:20] java expp1 popo
java.lang.NumberFormatException: popo
        at netrexx.lang.Rexx.dodivide(Rexx.nrx:1647)
        at netrexx.lang.Rexx.OpDiv(Rexx.nrx:1557)
        at expp1.main(expp1.nrx:6)

-- no input at all
sp069.marchesi ~/src/java/Java/bin [0:21] java expp1
java.lang.NumberFormatException:
        at netrexx.lang.Rexx.dodivide(Rexx.nrx:1647)
        at netrexx.lang.Rexx.OpDiv(Rexx.nrx:1557)
        at expp1.main(expp1.nrx:6)
........................................................

Those messages are really scaring, aren't they?

Handling exceptions: catch

Suppose that we have a block of code that, like in the example above, might generate an exception.

So:

 
   (...)
   -- this code might generate an exception
   --
   ...
   BLOCK_OF_CODE
   ...
   (...)
 

In NetRexx, if you want to handle exceptions, you'll write the above code as:

 
   (...)
   do
       -- this code might generate an exception
       --
       ...
       BLOCK_OF_CODE
       ...
     catch variable_name = EXCEPTION_NAME
       CODE_TO_RUN_IN_CASE_OF_EXCEPTION
   end
   (...)
 

In a nutshell, you put your code into a do ... end clause, and add a catch instruction. Program flow will be passed to CODE_TO_RUN_IN_CASE_OF_EXCEPTION in case of any EXCEPTION_NAME encountered

The special instruction is catch. Catch is (usually) followed by a statement of the format:

 
  catch error = EXCEPTION_NAME
    say 'EXCEPTION_NAME: got error:' error'.'
 

Always run a piece of code: finally.

Sometimes it is important to catch the exception, but also to be guaranteed that some "critical" code is run, whatever happens to the program, i.e. if the exception is cached or not. Think about a file lock, for example, that you MUST clean, in case of a program crash.

You use the finally statement, which you are guaranteed is ALWAYS run.

 
   (...)
   do
       -- this code might generate an exception
       --
       ...
       BLOCK_OF_CODE
       ...

     catch variable_name = EXCEPTION_NAME
       CODE_TO_RUN_IN_CASE_OF_EXCEPTION

     finally
       CODE_TO_RUN_ALWAYS_AND_ANYWAY

   end
   (...)
 

Resume

To resume what we saw so far:

 
  ...
  do                          
    ...                     -- This code MIGHT
    BLOCK_OF_CODE           -- generate an exception
    ...                     --
    catch [ err = ] EXCEPTION1
      ...                      --
      CODE FOR EXCEPTION1      --
      ...                      --
    catch [ err = ] EXCEPTION2
      ...                      -- You can catch as many
      CODE FOR EXCEPTION2      -- exceptions you want
      ...                      --
    finally
      ...                      -- code ALWAYS run
      CODE FOR EXCEPTION1      --
      ...                      --
  end

 

A revisited 'bad-programmer' inverse computation program

Let's apply what we saw so far to the example we initially made:

 
+----------------------------------------------------------------------+
| -- expp2.nrx                                                         |01
| -- WARNING: this is bad programming: no checks on input              |02
| --          data are performed                                       |03
| --                                                                   |04
| parse arg n                                                          |05
| ok = 0                                                               |06
| do                                                                   |07
|   inv = 1/n                                                          |08
|   say 'Inverse is:' inv                                              |09
|   ok = 1                                                             |10
| catch DivideException                                                |11
|   say 'Division exception'                                           |12
| catch ex=NumberFormatException                                       |13
|   say 'Number "'n'" bad for division.'                               |14
|   say 'message is "'ex'".'                                           |15
| end                                                                  |16
| if ok                                                                |17
|   then say 'Division is OK.'                                         |18
|   else say 'Problems found.'                                         |19
| exit 0                                                               |20
+----------------------------------------------------------------------+
                                                               expp2.nrx
Download the source for the expp2.nrx example
 
.......................................................
sp069.marchesi ~/src/java/Java/bin [0:29] java expp2 1
Inverse is: 1
Division is OK.
sp069.marchesi ~/src/java/Java/bin [0:29] java expp2 0
Division exception
Problems found.
sp069.marchesi ~/src/java/Java/bin [1:30] java expp2 toto
Number "toto" bad for division.
message is "java.lang.NumberFormatException: toto".
Problems found.
sp069.marchesi ~/src/java/Java/bin [1:31]
.......................................................

Output the stack trace information

The stack trace contains the information about your program at the time the exception occurred. In particular, it shows you the line number where the problem did occur. This might help you to solve a LOT of problems.

If you catch the exception, and you want to see the stack trace, you just add the following line:

 
  do
    (...)
    catch er = EXCEPTION
      say 'ERROR: EXCEPTION'
      er = printStackTrace()
  end
 

NOTE: printStackTrace() outputs to System.err, If you want the output to System.out, just type:

 
  er = printStackTrace(System.out)
 

Changing the format of the Stack Trace

Maybe you do not like the output format of the stack trace. This function will show you how to change it:

 
+----------------------------------------------------------------------+
| -- method......: dump                                                |38
| -- purpose.....:                                                     |39
| --                                                                   |40
|   method dump(e=Exception) public static                             |41
|     -- trace buffer                                                  |42
|     trace = Rexx(")                                                 |43
|                                                                      |44
|     -- get the error message                                         |45
|     --                                                               |46
|     err = e.tostring()                                               |47
|                                                                      |48
|     -- printStackTrace outputs to a PrintStream                      |49
|     -- we connect a PipedInput to grab the output                    |50
|     --                                                               |51
|     pout = PipedOutputStream()                                       |52
|     pin  = PipedInputStream()                                        |53
|     pin.connect(pout)                                                |54
|     out  = PrintStream(pout)                                         |55
|     in   = DataInputStream(pin)                                      |56
|                                                                      |57
|     -- get the stack                                                 |58
|     --                                                               |59
|     e.printStackTrace(out)                                           |60
|                                                                      |61
|     j = 0                                                            |62
|     loop while in.available() <> 0                                   |63
|       str = in.readLine()                                            |64
|       parse str 'at' rest                                            |65
|       if rest = '' then iterate                                      |66
|       j = j+1                                                        |67
|       trace[j] = rest                                                |68
|     end                                                              |69
|     trace[0] = j                                                     |70
|     parse trace[j] ':'line')'                                        |71
|     say '(dump) Error found line..:' line'.'                         |72
|     say '(dump) Message is........:' err'.'                          |73
|     say '(dump) Full dump follows.:'                                 |74
|     say                                                              |75
|     loop i = trace[0] to 1 by -1                                     |76
|       parse trace[i] p1'('prog':'line')'                             |77
|       if line = '' then iterate                                      |78
|       p1 = '('p1.space()')'                                          |79
|       say '(dump)' prog.left(12) p1.left(30) 'line:' line.right(5)   |80
|     end                                                              |81
|     say                                                              |82
|                                                                      |83
+----------------------------------------------------------------------+
                                                xsystem.nrx(Method:dump)
Download the complete source for the xsystem.nrx library

If we now modify our simple buggy program, like this:

 
+----------------------------------------------------------------------+
| -- expp2.nrx                                                         |01
| -- WARNING: this is bad programming: no checks on input              |02
| --          data are performed                                       |03
| --                                                                   |04
| parse arg n                                                          |05
| ok = 0                                                               |06
| do                                                                   |07
|   inv = 1/n                                                          |08
|   say 'Inverse is:' inv                                              |09
|   ok = 1                                                             |10
| catch er1 = DivideException                                          |11
|   xsystem.dump(er1)                                                  |12
| catch er2 = NumberFormatException                                    |13
|   xsystem.dump(er2)                                                  |14
| end                                                                  |15
| if ok                                                                |16
|   then say 'Division is OK.'                                         |17
|   else say 'Problems found.'                                         |18
| exit 0                                                               |19
+----------------------------------------------------------------------+
                                                               expp3.nrx
Download the source for the expp3.nrx example

we get the following result:

 
.......................................................
sp069.marchesi ~/src/java/Java/bin [0:69] java expp3 0
(dump) Error found line..: 8.
(dump) Message is........: netrexx.lang.DivideException: Divide by 0.
(dump) Full dump follows.:

(dump) expp3.nrx    (expp3.main)                   line:     8
(dump) Rexx.nrx     (netrexx.lang.Rexx.OpDiv)      line:  1557
(dump) Rexx.nrx     (netrexx.lang.Rexx.dodivide)   line:  1648

Problems found.
.......................................................

Summary.

 
 *** This section is: 
  
 *** and will be available in next releases


File: nr_17.html.

The contents of this WEB page are Copyright © 1997 by Pierantonio Marchesini / ETH Zurich.

Last update was done on 18 May 1998 21:47:54(GMT +2).