Errorbot
As he wrote with a pen in each hand,
And explained all the while in a popular style
If your users are bent on producing lots of errors you may wish to automate the documentation of them, via an “errorbot” which, without your intervention, quietly extracts the end-user environment and error information, and then (with a pen in each hand) writes it to log file, printer, web page and email.
Under Dyalog APL it is possible, but not straightforward, to create an environment that can automatically extract the ⎕DM and ⎕SI as text from a CONTINUE workspace. I will leave that as an exercise for the advanced user to work out. (I believe it is also now much simpler under Version 11 to extract this info from an APLCORE workspace.)
Alternatively, your bulldozer error trap can attempt to save this information at the point of the error into variables known to your pet errorbot, from where a simple ⎕CY command can extract it.
Code Snippet
N.B. The last (fourth) line of APL is split onto several lines, as shown by ellipses. ⎕ML is assumed to be 0 or 1. The code is ⎕IO-independent.
#.quaddm←⍬ ⍝ initialise ⎕DM store
#.quadsi←0⍴⊂'' ⍝ initialise ⎕SI store
continue←'''',(ExpandPath ⎕WSID,'..\..\continue.dws'),''''
⎕TRAP← (0 'E'(
… '⎕TRAP←(0 1000) ''S''
… ⋄ #.quaddm,←⎕dm
… ⋄ #.quadsi←↑⎕XSI,∘{''['',(⍕⍵),'']''}¨⎕LC
… ⋄ ⎕save ',continue,'
… ⋄ ⎕off '))
Restarting and Resetting
Just the place for a Snark! I have said it twice:
That alone should encourage the crew.
Just the place for a Snark! I have said it thrice:
What I tell you three times is true.
If you )XLOAD a CONTINUE workspace, it may be possible to correct the problem and then restart the workspace to test if the fix has worked.
File ties are independent of saving or loading workspaces. So an )XLOADed CONTINUE workspace will need any files retied before restarting.
I have found that by:
[1] using )RESET to clear the stack;
[2] running the workspace to a stop placed near where the error occurred;
[3] without untying the files, )XLOADing the CONTINUE workspace again
we are almost ready to restart the workspace.
Unfortunately, the CONTINUE workspace does not contain the ⎕PATH at the point of the error. So before restarting, you may need to set the ⎕PATH.
CONTINUE workspaces preserve even OLE links to Microsoft Word, etc.!
Now activate Debug Mode via Ctl-Enter, and you’re ready to roll. (Or at least roll over dead with the same error the user got.) If you can’t reproduce the error using his data, start by looking at the differences between his environment and yours.
A pre-Version 11 APLCORE cannot be )XLOADed but data may sometimes be copied into the active workspace with )COPY or ⎕CY. (An )XLOAD is preferable because it preserves the stack.)
To determine, without the stack, where the SYSERROR occurred, I find it useful to ⎕CY the whole of the APLCORE into a clear workspace, and then look at all the local variables.
)CLEAR
CLEAR WS
⍝ use ⎕CY because )COPY omits local variables
⍝ APLCOREs don't have .DWS extensions, so use full pathname
⎕CY 'C:\Dyalog\APLCORE.'
Since the local variables of functions on the stack at the point of the SYSERROR are accessible, their names and values can be used to determine which functions are in the stack. Distinctive local names help this process; reusing similar names, (e.g. x, y, r, data, text, mat, name) make it far more difficult.
“Two added to one – if that could but be done,”
It said, “with one's fingers and thumbs!”
Recollecting with tears how, in earlier years,
It had taken no pains with its sums.
If you really want to know exactly which functions are active at the time a SYSERROR occurred, try putting into every function a label that identifies the function’s name. For example, for a function Foo, name the label Lab_Foo.) Only the labels of functions in the stack will be ⎕CY copied from the APLCORE, so listing all variables starting with Lab_ will list all the functions on the stack at the time of the SYSERROR.
Unfortunately you can’t put a label in a D-function, but if the Dfn is dynamically created and localised, it is not a problem. Then the very fact that the Dfn has been copied by ⎕CY proves it was on the stack at the time of the SYSERROR.
Rules of Thumb
1. Untested code always fails in production.
2. Part-tested code that fails in production often does so on “edge conditions”.
3. That the code works with 2, 3 or 4 elements, but fails with a scalar, is a mistake typical of a newbie. A more experienced writer’s code might fail with zero elements. Well-tested code could still fail with twenty million elements (or fewer) due to WS FULL.
4. Virtually all code will fail at the extremes, or if the environment is changed.
“Have you stopped beating your wife yet?
A simple yes or no answer is all that is required.”
The fourth is its fondness for bathing-machines,
Which it constantly carries about,
And believes that they add to the beauty of scenes –
A sentiment open to doubt.
The following examples are all taken from the pensions industry.
A person’s sex, (ignoring sex changes, and other medical oddities) can simply be held as a Boolean, e.g. 0 for male and 1 for female. However there is a third possibility, “Not applicable”. The sex of someone’s spouse is N/A if there is no spouse. Hence the ‘3-way Boolean’: M for male, F for female and N for not applicable.
A frequent fault is caused by common code running off variable data.
One pension system I have worked on handles over 220 pension products from five former insurance companies, now all merged, but still having data held on the five original mainframe systems. Feeds from these differ by product and mainframe.
Failing to reconcile data codes resulted in errors. For example, when the code for a payment frequency (monthly, quarterly, half-yearly etc.) was set to A for ‘annual’ on one mainframe and Y for ‘yearly’ on another, errors were encountered.
Tip: When writing a case statement, list all known cases and let the default ELSE be an error. (Rival UK adverts come to mind: “Kills ALL known germs” “Kills 99.9% of all germs”.)
:Select payment_frequency
:Case 'M'
…
:Case 'Q'
…
:CaseList 'A' 'Y'
…
:Else
ERROR
:End
Do not be tempted to let the :Else replace the :CaseList 'A' 'Y'. That way, when the code gets a F (Fortnightly? Four-weekly?), it is rejected and does not default to the inappropriate Annual case.
“I said it in Hebrew – I said it in Dutch –
I said it in German and Greek:
But I wholly forgot (and it vexes me much)
That APL is what you speak!”
Well that’s all I have time for now.
“What’s the good of Mercator’s North Poles and Equators,
Tropics, Zones, and Meridian Lines?”
So the Bellman would cry: and the crew would reply
“They are merely conventional signs!”
(With apologies to Lewis Carroll, Douglas Adams, George Lucas, and Dyalog. However, I make no apologies whatsoever to the Spanish Inquisition or the comfy chair.)
Share with your friends: |