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, FALSE = 1 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
Richard M. Heiberger
2014-Oct-02 15:55 UTC
[Rd] debuggingState() analogous to tracingState() ?
Interesting timing. I could have used this additional control yesterday in class. I am teaching a graduate Statistical Computing class. Last night I went through the symbolic deriviatives (the deriv and D functions) in Section 9.6 of the Blue Book. The D function is recursive. I illustrated its behavior with debug(D) and then studied the statement D(expression(x^2+4), "x") At each step the console displays the entire switch() statement. And inside ESS the entire switch statement in the derivative.R buffer is highlighted. That is too much redundancy. I would like to have the .R buffer highlighted and maybe a truncated version of the statement displayed in the *R* (console) buffer. I am thinking of a trunctation similar to what C-c C-c in ESS does when it sends over a function definition. Somewhere around the third or fourth level of recursion I would truncate it even further. When investigating 3*x^2 + 4*x^5 It would be nice to see the detail of several levels of recursion for the 3*x^2 term and turn off the debug/trace behavior of the 4*x^5 term, with the debug/trace beahvior automatically coming back on when the two terms are merged. I discovered I would like an additional stop during debug. Here is a simple function to illustrate. simple <- function(x) { y <- x + x 2*y } debug stops before the 'y <- x+x 'and again before the '2*y' is evaluated and I can do regular browser investigations. When I hit enter, I want it to stop again after 2*y has been evaluated and before it returns to the console. I would like to investigate the result and then go back and investigate the intermediate variables with the result in view. Obviously I can redefine my own function to redesignedsimple <- function(x) { y <- x + x z <- 2*y z } but doing that to a function inside a NAMESPACE is very difficult to get right. Rich On Thu, Oct 2, 2014 at 10:55 AM, Martin Maechler <maechler at stat.math.ethz.ch> wrote:> 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, > FALSE = 1 > 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 > > _______________________________________________ > ESS-core list: https://stat.ethz.ch/mailman/listinfo/ess-core
Jonathan McPherson
2014-Oct-02 17:56 UTC
[Rd] debuggingState() analogous to tracingState() ?
> > > 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 > >Some observations from RStudio which may or may not be helpful: We don't expose any UI that allows the user to modify tracingState(). In fact, turning off tracingState() will make RStudio's breakpoints stop working (as they rely on trace()), without any warning or feedback from the UI. We've never received complaints about this, and so my presumption is that very few people need to turn off tracing globally, and those who do know what they're doing and/or aren't using the IDE debugging features. Some mechanism for globally altering debugging state would be very useful. Right now we have a problem wherein during debugging the R functions RStudio calls to e.g. analyze and compose the list of objects in the workspace are themselves debugged. Today we're solving this by manually tripping the RDEBUG flag on an environment before we evaluate expressions in it, which I think we can all agree is less than ideal. Do you foresee any non-interactive use for debuggingState()? If so, it might be nice if the state had push/pop rather than on/off semantics, to make the pattern of disabling locally easier to express. > the ability to add a breakpoint to a function that is > currently being evaluated. Yes, this would be useful to us, although unless I'm missing something it seems pretty orthogonal to the rest of the thread. It's not a common feature request. One thing that would be useful is some officially supported way to debug during source(). Lots of people don't use functions and just have R scripts full of straight-line statements (sometimes containing references to other code via source()). RStudio will let you set breakpoints on top-level statements, and this has proven to be a popular feature, but its implementation is very messy--we effectively create a function from the statements in the file and then use the function debugger, which works for simple scenarios but starts falling apart if you do anything complicated. Thanks, Jonathan. [[alternative HTML version deleted]]
Stephan Wahlbrink
2014-Oct-02 19:59 UTC
[Rd] debuggingState() analogous to tracingState() ?
The possibility to temporarily turn off debugging sounds interesting. A short comment at the end Am 2014-10-02 um 16:55 schrieb Martin Maechler:> 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, > FALSE = 1 > 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 think a common pattern could be: state <- debuggingState(FALSE) # disable debugging # run special code... debuggingState(state) # restore state If the first line disables both, debugging _and_ tracing, it would be convenient if the last line restores the exact state; also mixed state like debugging= on but tracing= off, if tracing was disabled. Stephan