Node:Specific and Generic Breakpoints, Next:Breakpoint Actions, Previous:Breakpoint Tests, Up:Advanced Debugging
In all the examples so far a breakpoint was put on a specific predicate,
described by a goal
or pred
test. Such breakpoints
are called specific, as opposed to generic ones.
Generic breakpoints are the ones which do not specify a concrete
predicate. This can happen when the breakpoint spec does not
contain goal
or pred
tests at all, or their argument
is not sufficiently instantiated. Here are some examples of generic
breakpoints:
| ?- add_breakpoint(line('/home/bob/myprog.pl',6), _). % Generic spypoint added, BID=1 yes | ?- add_breakpoint(pred(foo/_), _). % Generic spypoint added, BID=2 yes | ?- add_breakpoint([goal(G),true((arg(1,G,X),X==bar))], _). % Generic spypoint added, BID=3 true ?
The first breakpoint will stop at all calls in line 6 of the given
file, the second at all calls of a predicate foo
, irrespective of
the number of arguments, while the third one will stop at any predicate
with bar
as its first argument. However, there is an additional
implicit condition: the module name expansion inserts the type-in module
as the default module name in all three cases:
Breakpoints: 3 # generic if [goal(user:A),true(user:(arg(1,A,B),B==bar))] 2 # generic if [pred(user:foo/A)] 1 # generic if [goal(user:A),line('/home/bob/myprog.pl',6)]
Notice that even the breakpoint with BID 1, which originally contained a
single line
condition, has been expanded to include a goal
test, with the type-in module name. To get rid of it, you have to
provide an explicit anonymous variable module name in front of the
breakpoint spec. In the other two examples you can include an anonymous
module prefix in the argument of the goal
or pred
test:
| ?- add_breakpoint(_:line('/home/bob/myprog.pl',6), _). % Generic spypoint added, BID=1 yes | ?- add_breakpoint(pred(_:foo/_), _). % Generic spypoint added, BID=2 yes % zip,source_info | ?- add_breakpoint([goal(_:G),true((arg(1,G,X),X==bar))], _). % Generic spypoint added, BID=3 true ? yes | ?- debugging. (...) Breakpoints: 3 # generic if [goal(A:B),true(user:(arg(1,B,C),C==bar))] 2 # generic if [pred(A:foo/B)] 1 # generic if [line('/home/bob/myprog.pl',6)]
Generic breakpoints are very powerful, but there is a price to pay: the zip debugging mode is slowed down considerably.
As said earlier, in principle the debugger is entered at each port of each procedure invocation. As an optimization, the debugger can request the underlying Prolog engine to run at full speed and invoke the debugger only when one of the specified predicates is called. This optimization is used in zip mode, provided there are no generic breakpoints. In the presence of generic breakpoints, however, the debugger has to be entered at each call, to check their applicability. Consequently, with generic breakpoints, zip mode execution will not give much speed-up over debug mode, although its space requirements will still be much lower.
It is therefore advisable to give preference to specific breakpoints
over generic ones, whenever possible. For example, if your program
includes predicates foo/2
and foo/3
, then it is much
better to create two specific breakpoints, rather than a single generic
one with conditions [pred(foo/_),...]
.
spy/2
is a built-in predicate which will create specific
breakpoints only. Its first argument is a generalized predicate spec,
much like in spy/1
, and the second argument is a breakpoint
spec. spy/2
will expand the first argument to one or more
predicate specs, and for each of these will create a breakpoint, with a
pred
condition added to the test part of the supplied
breakpoint spec. For example, in the presence of predicates foo/2
and foo/3
| ?- spy(foo/_, file(...))
is equivalent to:
| ?- add_breakpoint([pred(foo/2),file(...)], _), add_breakpoint([pred(foo/3),file(...)], _).
Note that with spy/[1,2]
it is not possible to put a breakpoint
on a (yet) undefined predicate. On the other hand,
add_breakpoint/2
is perfectly capable of creating such
breakpoints.