Debug infrastructure makes a distinction between topics as "string" and as "atom" (was: how do I enable debug messages in another module?)

Suppose I have this little module (for dict methods plus a standard predicate):

:- module(point, [point_length/2]).

M.multiply(F)                           % Method ".multiply/1" on dict M
   := point{x:X, y:Y}                   % Returns a "point" dict
   :- X is M.x*F, Y is M.y*F.           % Body where dict M is accessible 

M.len()                                 % Method ".len/0" on dict M
   := Len                               % Returns a "Len" value (a number, actually)
   :- Len is sqrt(M.x**2 + M.y**2),     % Body where dict M is accessible
      debug("pointlength_method","~q.multiply(~q) = ~q",[M,Len]).
      
point_length(point{x:X,y:Y},Len) :-    
   Len is sqrt(X**2 + Y**2),
   debug("pointlength_predicate","point{x:~q,y:~q} = ~q",[X,Y,Len]).

And so:

?- list_debug_topics.                 
---------------------------------------------
Debug Topic               Activated To
---------------------------------------------
true.

Load module then

?- [module_point].                    
true.

?- list_debug_topics.
---------------------------------------------
Debug Topic               Activated To
---------------------------------------------
pointlength_method            false []
pointlength_predicate         false []
true.

No output as expected:

?- point_length(point{x:12,y:13},L).
L = 17.69180601295413.

I want output:

?- debug(pointlength_predicate).
Warning: pointlength_predicate: no matching debug topic (yet)
true.

?- list_debug_topics.
---------------------------------------------
Debug Topic               Activated To
---------------------------------------------
pointlength_method            false []
pointlength_predicate         false []
pointlength_predicate          true [user_error]
true.

The above is weird, with two entries for the same topic. And there is no output still:

?- point_length(point{x:12,y:13},L).
L = 17.69180601295413.

Maybe like this?

?- debug(point:pointlength_predicate).
Warning: point:pointlength_predicate: no matching debug topic (yet)
true.

?- list_debug_topics.
---------------------------------------------
Debug Topic               Activated To
---------------------------------------------
pointlength_method            false []
pointlength_predicate         false []
pointlength_predicate          true [user_error]
point:pointlength_predicate    true [user_error]
true.

NOPE!

?- point_length(point{x:12,y:13},L).
L = 17.69180601295413.

How is it done?

Update

Badonk!

?-  debug("pointlength_predicate").
true.

?- point_length(point{x:12,y:13},L).
% point{x:12,y:13} = 17.69180601295413
L = 17.69180601295413.

Oh yeah.

debug infrastructure makes a distinction between atoms and strings as topics… probably not what one wants?

OTOH, you can dump any (ground) term in there.

?- debug(f(x,y)).
Warning: f(x,y): no matching debug topic (yet)
true.

?- list_debug_topics.
---------------------------------------------
Debug Topic               Activated To
---------------------------------------------
pointlength_method            false []
pointlength_predicate          true [user_error]
point:pointlength_predicate    true [user_error]
pointlength_predicate          true [user_error]
f(x,y)                         true [user_error]
true.

Hmmm…

1 Like

Debug channels are based on unification. That is quite deliberate. Notable it allows creating sub topics using http(post), http(get), etc. To debug all HTTP, use

?- debug(http(_)).

With some tactical choice of terms you can make quite sophisticated selections of debug topics easily.

Strings vs. atoms is not really settled. I guess the rough idea is to use atoms for identifiers that you want to test for being (non-)equal and strings for stuff such as format/3 format arguments. Strings can also be useful to represent highly volatile text. Volatile atoms are placed in the atom table and require to be garbage collected.

The above has worked quite well for ECLiPSe that always has strings and did not have atom garbage collection. SWI-Prolog introduced strings much later and does have atom garbage collection, making the best practices a bit difficult.

Surely, use atoms for debug topics!

2 Likes

Thanks Jan. Should list_debug_topics/0 indicate whether it has a string on hand or an atom? It might be informative.

I have added your note to the comment section in the manual. At some point I will update the manual accordingly (where does all my time go?)

2 Likes

Its not a big deal, but I switched to quoted write with named variables to make the listing unambiguous. Would have prevented this discussion :slight_smile:

2 Likes