[m-dev.] proposed command set for the internal trace based debugger

Fergus Henderson fjh at cs.mu.OZ.AU
Tue Jun 2 16:38:25 AEST 1998


On 02-Jun-1998, Peter Schachte <pets at students.cs.mu.oz.au> wrote:
> On Mon, 1 Jun 1998, Zoltan Somogyi wrote:
> 
> > break points:
> > The user may associate a break point with a specific goal path within
> > a predicate. Break points have the same states and the same effects as spy
> > points. XXX should an empty goal path cause a break on all of the
> > CALL, EXIT and FAIL ports (the interface ports), or only on the CALL port?
> 
> I'm not sure I understand the difference between break and spy points.

My intent in suggesting the distinction was that a break point
would stop at only one port, whereas a spy point would stop at
all ports.

When adding a break point, if you just specify the predicate name,
without specifying a port, then it should default to the "CALL" port.
But a break point specifier should include an optional port,
so that you can set a break point on the "FAIL" port of a particular
predicate, for example.

> Is a break point just a spy point on a particular (lexical)
> atom?

In theory, both break points and spy points could apply either to predicates
or to subgoals.  You could have CALL/EXIT/REDO/FAIL ports for each subgoal,
and a break point would apply to only one of them, whereas a spy point
would apply to all of them.

However, with the current implementation, we do not have all four ports;
for predicates, we have just CALL/EXIT/FAIL, while for subgoals,
we have a seperate port types for each different kind of subgoal, but
these are all basically just different kinds of CALL ports.

Thus with the current implementation the distinction between
spy points and break points only makes sense for predicates, not
for subgoals.  The debugger should report an error if the user
tries to set a spypoint on a subgoal.

> Or by "goal path" do you mean something like "the second call
> to foo/4 in the fourth clause of bar/2 when called from the first call
> to baz/5 in the first clause of zip/2 if it was called from the third
> call to zap/2 in the eighth clause for zop/2...."

A goal path specifies a subgoal within a predicate, e.g.
"the else part of the if-then-else in the second disjunct of foo/4".

> It would be very useful to be able to (separately) turn on and off stopping
> and printing based on port. 

Yes.  You should be able to do this by using breakpoints instead of spypoints.

> It would also be good to have a way to turn off printing (and maybe to turn
> it on, as well) for all subgoals of a certain goal, or subgoals of a certain
> predicate.  Ideally, there would be a stateless (just zip through this goal
> now without stopping or printing anything:  skip in Prolog debuggers) and a
> stateful (until I say otherwise, always zip through calls to this predicate
> (or this lexical call to this predicate)) without stopping or printing
> anything.
> 
> 
> > 	An empty command line is interpreted as "skip 1".
> > 	XXX or maybe an empty command should do nothing?
> 
> How about allowing users to alias "" to do whatever they want?

Yes, I think that would be a good idea.
If the parser reads in "", it can replace it with "default_command",
and the user can alias "default_command" to anything they like.

But I think "skip 1" is a good default alias for the default command.

> > redo
> 
> Since this command, as far as I know, only exists until now in Prolog
> debuggers, and Prolog debuggers call this "retry," and use "redo" to
> mean something completely different, how about calling this "retry?"
> You'll cause less confusion.

Actually NU-Prolog calls it "redo".

Arguably the names used by other Prolog debuggers such as SICStus are
a poor choice: it would make more sense to call the port "RETRY"
and the command "redo".

> Wouldn't it be possible to have a debug version of the library that
> makes file opening and closing commands "trail" their effects so they
> can be redone?  Ideally it would be possible for writers of libraries
> containing destructive modes to also write mostly destructive versions and
> have the debugger optionally use those instead in a systematic way, so they
> could be retried.  Note that when code is being "skipped" over (in Prolog
> terminology), you can just use the destructive version, for full speed and
> lower memory usage.

This is all a good idea; are you volunteering to implement it? ;-)

> One other command that would be useful (if it's implementable) would
> be to replace the goal at the current port with one the user types in.
> The user's goal would be able to include the variables appearing in
> the goal at the current port.  This would be useful when you've found
> a bug, and you'd like to keep going and find the next, so you just
> want to supply the correct result for a goal and keep going.

I don't think this would be very useful, especially in comparison to the
likely difficulty of implementation.

Being able to edit your source file, dynamically load it in,
and continue debugging the same run (using the "retry" or "redo"
command to re-execute the bit you just fixed) would be useful --
that allows you to quickly test a bug fix.  I have used that
feature in NU-Prolog and SICStus quite a bit.

> > stack
...
> It would be useful to have this print a number for each stack frame, and to
> have a command like up and down (maybe "show" or "goto"?) that takes one of
> these numbers and makes that the current frame directly. 

Yep.  I suggest "frame" for the name of that command.

> > spy <module name> <predicate name>
> 
> I think it would be better to use the standard module:name/arity
> syntax to spy predicates.  As a convenience to users, it'd be good to
> allow everything but name to be omitted, treating the omitted items as
> wildcards, and to then spy every matching predicate.
> 
> Also it's nice to be able to spy multiple predicates in one command.

I think these are good suggestions.

> > 	named module. (XXX Should it be on all the interface ports, i.e.
> > 	CALL, EXIT and FAIL?)
> 
> You seem to have omitted the REDO port.  That one's pretty important.

Our execution mechanism optimizes away the REDO port.
Instead, execution jumps directly to the place where execution will
resume (i.e. a DISJ port).  

It would be nice if it were possible for the debugger to 
simulate the REDO port, but implementing that looks to be
fairly tricky, especially if you want the result to be at all
efficient.

> > here
> > 	Puts a break point on the predicate referred to by the current event
> > 	at the goal path named by the current event.
> 
> I think it would be much better to have a syntax for specifying "here"
> as a predicate spec in spy and break commands.

Yes, I agree.

In fact I think the syntax should be

	spy [optional predicate spec]
	break [optional predicate spec]

and if you omit the optional predicate spec it should default to
"spy here" or "break here".

"spy here" should only be allowed at the main CALL, EXIT, and FAIL ports,
not at internal ports.

> Also, does all of this work exactly the same for functions?  Maybe
> there should be a syntax for spying functions, in case there is a
> function and predicate with the same name and arity?

Yes, a predicate spec could include an optional "pred" or "func" prefix.

	mdb> spy pred foo:bar/2
	mdb> break func foo:bar/1

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3        |     -- the last words of T. S. Garp.



More information about the developers mailing list