[comp.lang.apl] debuggers

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)