![]() |
The NetRexx Tutorial
![]() |
In this chapter we will analyse how to better control the program flow of a NetRexx application.
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).
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.
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 | ![]() |
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?
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'.'
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 (...)
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
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 | ![]() |
....................................................... 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] ....................................................... |
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)
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) | ![]() |
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 | ![]() |
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. ....................................................... |
*** This section is:*** and will be available in next releases