[Rd] debuggingState() analogous to tracingState() ?

Martin Maechler maechler at stat.math.ethz.ch
Thu Oct 2 16:55:34 CEST 2014

We have had some conversation within R core, 
lead by Duncan Murdoch and me, about a proposal
to extend  the current  tracingState() functionality
by something tentatively called debuggingState().

Duncan has allowed me to copy the previous conversation
(after very minor editing):

The following is quite technical and assumes you know more about
R's debug()ing and trace()ing than an estimated 99.9% of the R users:

>>>>> Duncan Murdoch <murdoch.duncan at gmail.com>
>>>>>     on Thu, 2 Oct 2014 07:19:34 -0400 writes:

 > On 02/10/2014, 6:36 AM, Martin Maechler wrote:
 >>>>>>> Duncan Murdoch <murdoch.duncan at gmail.com>
 >>>>>>> on Thu, 2 Oct 2014 05:41:00 -0400 writes:
 >> > On 02/10/2014, 5:17 AM, Martin Maechler wrote:
 >> >>>>>>> Martin Maechler <maechler at stat.math.ethz.ch>
 >> >>>>>>> on Sat, 27 Sep 2014 22:55:21 +0200 writes:
 >> >> 
 >> >> > It would be really nice to temporarily disable debugging similar to
 >> >> > tracingState() being able to turn of trace()ing.
 >> >> 
 >> >> > In eval.c  the corresponding C code would be used as the  tracingState()
 >> >> > analogue is used.
 >> >> 
 >> >> > [...........]
 >> >> > ???
 >> >> 
 >> >> It seems to work ok, the few cases I've tried.
 >> >> 
 >> >> I wonder a bit about the R / C interface.
 >> >> Using an extra function  debuggingState() seems a bit of a
 >> >> waste, and I was thinking of enhancing
 >> >> tracingState() from a 1-argument to a 2-argument form.
 >> >> 
 >> >> something like
 >> >> 
 >> >> tracingState <- function(on = NULL, debug = on)
 >> >>         .Internal(traceOnOff(on, debug))
 >> >> 
 >> >> but I don't see how to keep usages such as
 >> >> 
 >> >>   on <- tracingState(FALSE)	 # turn it off QUICKLY (via a .Internal)
 >> >>   if(on) {
 >> >>     on.exit(tracingState(TRUE)) # restore on exit, keep off during trace
 >> >>     ............
 >> >>   }
 >> >> 
 >> >> working back compatibly. 
 >> >> 
 >> >> We could think of tracingState() only returning length one when
 >> >> called with one argument, and returning length two when called
 >> >> with a second argument... but that seems messy.
 >> >> 
 >> >> If nobody has a better idea, I'd commit a new   debuggingState() 
 >> >> function which is very much "parallel" to  tracingState().
 >> > It's hard to comment on this, because I don't know exactly what
 >> > behaviour is controlled by the debugging flag.  
 >> Good point.  The flag, accessed via RDEBUG(.), is used in quite a few places,
 >> and the intent and my experiments have replaced
 >>      RDEBUG(.)
 >> by   RDEBUG(.) && R_current_debug_state()
 >> in some places, but not in most places.
 >> > Will it cause an
 >> > explicit call to browser() to be a no-op, or does it just control breaks
 >> > triggered by entry into a function that has been marked by debug()?
 >> What would you want?  Probably the latter, right?
 >> With my use case below, however, I could argue I'd even want  browser()
 >> to be a no-op in that case.  It is not so important to me.
 >> > What is the effect of a call to a function marked with debugOnce()?
 >> Good question.  Here my code was such that the function would also
 >> not have been debugged.
 >> But of course, that is open for "debate",  and I am glad you've
 >> started / continued the discussion.
 >> My main use case for
 >>         debuggingState(FALSE)
 >> would be when I want to call some R function that  "just runs
 >> through" and gives me its result, even though the user may have
 >> added the debug flag to a very basic R function which is called
 >> by my R function.
 >> Given these question, you could start arguing we'd want more
 >> than just  TRUE or FALSE for debugging state,
 >> just so one could apply differing behaviour in the above cases.

 > Or the alternative:  expand the use of the tracingState() flag to affect
 > RDEBUG as well.

Indeed.  If we additionally want to remain backcompatible, I think,
we'd need to add new values in addition to {TRUE, FALSE} (and
NULL for input).

E.g., --- making up something to be improved ---
using bit patterns which when added give an integer "tracing+debugging-state"

1 : tracing-turned-off
2 : debugging turned off, allowing browser() and debugonce()
4 : making browser()   a no-op
8 : making debugonce() a no-op

and hence 1+2+4+8 = 15 turns off all "browsing/debugging"
for which I'd typically want a convenient short cut.

for back compatibility,
TRUE  = 0

I'd use UI with a vector of character strings, that can be
translated to integer codes entirely analogous to
.deparseOpts()   {used from deparse(), dput() and dump()}.


A considerably simpler interface which would be good enough for
my use, was to simply add a new  debuggingState() function with
TRUE/FALSE option, and we would just have to decide how much
"turning off debugging" should happen when the state is set to FALSE.
In that case, I would still like the ability (on the level of R)
to simultaneously turn off debugging and tracing and turn them
back on as easily.  So I'd consider setting up debuggingState()
in a way that it can simultaneously turn off and on both tracing
and debugging.

 > I don't have much of an opinion on these questions.  I've never used the
 > tracingState() function, though I use trace() all the time (via
 > setBreakpoint()).  You might want to consult people who write debugger
 > front-ends.  

which I am now doing: I'm including ESS-core, 
Jonathan (RStudio) and Tobias (StatET) which Duncan mentioned as
being interested and having asked for better debugging support
functionality in the past, such as

 > the ability to add a breakpoint to a function that is
 > currently being evaluated. 

So, after quite a bit of musing, we are grateful for your
thoughtful comments on this
(and yes: I am fan of  "keep it simple!"  and  "small is beautiful!"
 also inside R's code base).

Martin Maechler,
ETH Zurich

More information about the R-devel mailing list