Peter Jipsen writes in his e-mail message of 6-Nov-92:
Is it possible to trace through gap code?
Are there some useful commands to help debugging
Well there is a function in the GAP kernel that switches a flag for a
function. Afterwards this function prints out its arguments whenever it
is called and its result whenever it is done. This function is called
'TraceFunc' and the corresponding function is called 'UntraceFunc' (or is
it only 'Untrace', I can't remember). Unfortunately this function is
next to useless because it simply produces too much output.
I found out about Backtrace in some
message on this forum, but couldn't find it
in the manual.
Yes it is simply an oversight that 'Backtrace' isn't in the manual. (I
guess this could happen because everyone of us used it so much that we
never had to look it up in the manual ;-)
Of course one can always interrupt
execution and inspect variables (very useful) and
after inserting enough ugly print statements in the
clean (but errant) gap code
one can eventually figure out what went wrong,
but then everything needs to be cleaned back up.
Yes, we do this a lot. (A side note. When I am looking for a bug I use
lots of print statemtents or other tools. But more often than not I
finally nail it down while not sitting at the terminal or reading the
code. It happens quite often on my way home.)
Maybe other users have come up with more
Werner made one suggestion in his message. I address this below.
I guess in an ideal world only bug
free code would be written, and gap goes a long way
towards implementing mathematical algorithms in a
You might just as well say that in an ideal world we would know the
answers to all (important) questions and wouldn't need to employ
computers at all.
but with the innovative semantics of
list assingment I have managed to create some rather
Yes, the list assignment is the major stumbling block for almost
everyone. Especially those who had previously experience with Pascal, C,
or Fortran. (Is anybody reading this forum who was used to Lisp and
found GAP's semantics quite natural?)
Even so, writing gap routines is in my experience far
less time consuming that using traditional programming
Depends on the problem of course. But yes, for mathematical stuff this
was our hope and is our experience too.
Werner Nickel answered less than 2 hours later:
Instead of interrupting an execution and end up at a more or
less random point in the GAP code one can use the function
Error() to halt the execution of GAP code at specific points.
As soon as Error() is executed, GAP goes into a break loop and one
can have a look at the state of the execution at this point. It is
possible, of course, to continue the execution by `returning' from
the break loop.
Indeed this is better than ordinary print statements, because one can do
more things in the break loop. (Of course one could use '1/0;' instead
Still there are several problems with this approach. The first is that
the bug may not be in your function but in a library function, and you
may not have write permissions to edit the file in order to put a call to
'Error' into the function.
The other problem is more serious. Suppose you have a larger function.
You have edited it, and it now contains a call to 'Error()'. So you work
your way through the execution. After quite some time you finally see
something and you say to yourself ``Ah, I shouldn't be looking at this
loop, this loop is probably o.k. Instead I should be looking at this
other loop.'' Then you would have to terminate your execution, edit the
file again, and *start all over again*. This is very annoying.
This technique suggests a way of implementing a step by step execution
of GAP code. The user would tell GAP at some point that she wants to
start to trace through the GAP code step by step. This could be done
by calling an internal function (which would have to be inserted at
some point into the GAP code). From then on, the internal functiont
which is responsible for executing a sequence of GAP statements could
generate a call to Error() after each statement has been executed. It
would also be useful to choose specific functions for step by step
execution. In this case a break loop would be created after each
statement in one of the chosen functions has been executed.
I don't know how difficult it would be to make the necessary changes
to the GAP kernel. At a superficial level it does not look to be too hard.
Any comments ?
(You knew I wouldn't resist ;-)
Let me put it this way. Since the GAP kernel is an interpreter (and so
the machinery to evaluate arbitrary expressions is always available),
since break-loops are already there, and since the functions of the
interpreter that implement the (GAP level) function calls leave lots of
information around (which is used e.g. by 'Backtrace'), most of the
machinery to do all kinds of nice things is there. Breakpoints that can
be dynamically set and unset, single stepping, even a limited form of
watchpoints, should all be possible.
Still there are a few tricky issues. The first is how to specify where
to put a breakpoint. This will probably require that GAP keeps track of
linenumbers. For another example if one wants breakpoints with
conditions (e.g., break at line 123 but only if i <= 0), then it is not
so easy to ensure that the variable references ('i' in this case) are
evaluated in the right environment (e.g., we probably don't mean the
global variable 'i', but whatever variable would be referenced by 'i' in
We are in contact with Benno Fuchsteiners group in Paderborn. They have
implemented a very nice debugger for a system that is implemented similar
to GAP. We will see what of their ideas, or maybe even of their code, we
-- .- .-. - .. -. .-.. --- ...- . ... .- -. -. .. -.- .- Martin Sch"onert, Martin.Schoenert@Math.RWTH-Aachen.DE, +49 241 804551 Lehrstuhl D f"ur Mathematik, Templergraben 64, RWTH, D 51 Aachen, Germany