hafer@infbs (Udo Hafermann) (10/12/88)
Could anyone point to references on techniques or systems for interactively debugging APL programs?
jaxon@uicsrd.csrd.uiuc.edu (10/14/88)
I don't understand the question. The interpreter itself (even one that implements the barest minimum required by the APL standard) already supplies 95% of the features offered by the best interactive debuggers for other languages. You should be able to use #TRACE and #STOP (formerly Tdelta and Sdelta) to inspect its run time behavior. Extensions like monitorred variables, exception handling, trace windows, on-line help and others are not standard, but they are available from some APL vendors. If you want hints about how to tackle writing a debuggable program... 1) Write components that check their arguments, environment & results. Write the checks as separate lines that halt the program when the check fails. You can filter them out once its time to cut a production version. 2) Don't optimize anything until most of the design bugs have been found and fixed. 3) Write up a test program that unit tests components; Write a test script that integration tests the whole system; Rerun the tests frequently while you're fixing bugs. A few years ago Jim Ryan marketted an Sharp APL application that was a "programmer's workbench" (1981-83?) IPSA or STSC probably have similar packages that help automate some of the program maintenance phase. There are some particular kinds of bugs for which APLers have developed clever debugging methods, but I don't think anyone has published a collection. Linda Alvord wrote an instructive paper for APL81 or APL83 covering APL "learning bugs", and there are certainly some bugs more common than others. Your question raises a lot of issues some dull, some deep. Which ones should we try discussing in this notesfile? Maybe just anecdotes like "The toughest bug I ever fixed..." or "My worst coding error..." would be entertaining. I could suggest a few broad categories: Name conflicts due to dynamic scoping. Numerical precision problems (especially in portable software) Rank and shape errors. "How DID that variable get the value 0?, and how am I going to find the function that did it?" "It looked origin-independent, but it wasn't" IMPLICIT ERROR Exactly what order are names dereferenced and functions evaluated anyway? My predecessor left 500 one-liners and no documentation. or worse: I believed the comment, now if only the interpreter could read it! This newsgroup has been too dull lately, write something...
ljdickey@water.waterloo.edu (Lee Dickey) (10/15/88)
In article <109@infbssys.infbs> hafer@infbssys.UUCP (Udo Hafermann) writes: >Could anyone point to references on techniques or systems for >interactively debugging APL programs? Dear Udo, Two books recently mentioned in this news group might be some help: APL: an introduction 1986 Howard A. Peele Hold, Rinehard and Winston ISBN 0-03-004953-9 APL: An Interactive Approach, Third Edition 1984 Leonard Gilman and Allen J. Rose John Wiley & Sons, Inc ISBN 0-471-80585-8 Another book, not for the beginner, is APL: Advanced Techniques and Utilities 1987 Gary A. Bergquist Zark Incorporated, 53 Shenipsit St, Vernon, Connecticut 06066 ISBN: none? The two system functions: Quad STOP can be a big help, because you can stop your function before it executes any given line and query the variables. Similarly, you can use Quad TRACE to print the result value on any line. The system command )SI can also be a help. And, of course, )VARS sometimes helps. As to program style, vertical layout of your function will help you to debug it and read it again after a year has passed. As a rule of thumb, do not use more than one assignment per line. OK? -- L. J. Dickey, Faculty of Mathematics, University of Waterloo. ljdickey@WATDCS.UWaterloo.ca ljdickey@water.BITNET ljdickey@water.UUCP ..!uunet!watmath!water!ljdickey ljdickey@water.waterloo.edu
raulmill@sal4.usc.edu (Raul Miller) (10/18/88)
In article <49700004@uicsrd.csrd.uiuc.edu> jaxon@uicsrd.csrd.uiuc.edu writes: > If you want hints about how to tackle writing a debuggable program... > 1) Write components that check their arguments, environment & > results. Write the checks as separate lines that halt the > program when the check fails. You can filter them out once > its time to cut a production version. > > 2) Don't optimize anything until most of the design bugs have been > found and fixed. > > 3) Write up a test program that unit tests components; > Write a test script that integration tests the whole system; > Rerun the tests frequently while you're fixing bugs. > More generally: Always include comments describing any variables used to communicate between a function or defined code sequence and the rest of the world. Rarely comment on the code itself. Next write the code that goes with the comments. When you debug, you want to make sure that what is going in and out of the function matches the comments. quadTRACE and such are useful here for isolating problems within a function. A general troubleshooting technique you should be familiar with is isolating cause and effect. This can be done by starting at the beginning of a flow and tracing it through to where it deviates from the ideal. This can also be done by forcing data in at some point and making sure that it is handled properly from that point on. One of the most important debugging/analysis 'techniques' anywhere is knowing how things should be when they are working right. This allows you to recognize where they are wrong. In APL, this can generally be achieved by commenting variables (commenting the workspace can help too...). Finally, if you are dealing with big workspaces or sets of workspace, you'll need to have some tools to show the hierarchy between the different modules. Some of these can be generated automatically (for example, showing the graph structure of which functions call which functions in a workspace). Others will have to be generated by the originator of the programming (for example, the purpose of a directory or workspace). Essentially, what I am trying to say is debugging a program you understand is trivial. The trick is understanding it. I hope you find the above useful. Raul Miller USENET: raulmill@oberon.usc.edu
hafer@infbs (Udo Hafermann) (10/18/88)
Sorry, I should have been a little more specific. Of course: APL already provides an excellent environment for program development, but this is due mainly to the concept of interpretation as such. As we are working on visualizing APL concepts to aid learning APL, I would be interested in more specific pointers to the packages mentioned. E.g., has no-one felt the need to single-step through the execution of an APL function, watching the values of variables change (in an extra window, for instance)? Personally, I find the Trace- and Stop-primitives just too primitive.
jaxon@uicsrd.csrd.uiuc.edu (10/18/88)
>> Rarely comment on the code itself.
I would go farther than that: NEVER leave a comment that merely restates
what the APL code is doing. When you are hunting down bugs later on,
there is a huge temptation to BELIEVE such comments when your code in
fact does something else. Worse still, if the code is right and the
comment is inaccurate, you stand a chance of misusing the function or of
"correcting" it to match the (erroneous) comment.
The little "lamp" symbol is intended to light your way through the code.
I generally use it to describe the goal of the next several function lines.
Comments that describe a function's arguments, result and (do you really
use?) global side-effects should meet the same criteria: State the
purpose of the argument, not the rules for what is and isn't a legal
argument. I've always been torn between the higher performance of
a one-liner utility routine that expects its caller to supply correct
arguments and the safety of a routine that checks everything before it
does its job. Every program has different needs , and fortunately APLs
offer a couple of approaches.
1) #ER or #ERR or some such system function that raises a regular
APL error signal. When Steve Bartels and I designed APLB we put in
a #ER that does nothing if its argument is empty and otherwise signals
an error with the argument as the error message. We use it for
ASSERTION CHECKING, for example:
#ER (~2|ARG)/'THE LEFT ARGUMENT MUST BE A SINGLE ODD INTEGER'
2) Sometimes the checks take more time than the function. I can't
stand the thought of clogging a perfectly clear one-liner with
inane tests. In these cases I write a "cover function" that
does all the inane tests, then calls my one-liner. When I want the
high performance version I )COPY in a group that replaces
the cover functions by their formula 1 race car guts. (Seat belts
not available.)
3) APL primitives do a lot of checking themselves. In the above
example I checked for odd ARGs, but the APL "not" (~) checked
for integers, and the "replicate" (/) gets some length or rank
error if ARG isn't scalar (or exactly the length of my message).
The important thing is that the program stops on a line that
expresses some constraint that has been violated, or some
assumption that turned up false. Errors reports are our friends!
...well more like relatives actually...
Comments have never done much for me, I only believe what I read in
the code. So when I need support to believe that the code is correct
I write code that documents my intentions, not comments.
regards - Greg Jaxon (jaxon@uicsrd.uiuc.edu)