Learn R Programming

debug (version 1.2.4)

debug-package: How to use the debug package

Description

debug is an alternative to trace and browser, offering:
  • a visible code window with line-numbered code and highlighted execution point;
  • the ability to set (conditional) breakpoints in advance, at any line number;
  • the opportunity to keep going after errors;
  • multiple debugging windows open at once (when one debuggee calls another, or itself);
  • full debugging ofon.exitcode;
  • the ability to move the execution point around without executing intervening statements;
  • direct interpretation of typed-in statements, as if they were in the function itself.
Even if you don't write functions, or even if you don't write buggy functions, you may find it helpful to run the debugger on functions in package:base or other packages. Watching what actually happens while a function is executing, can be much more informative than staring at a piece of code or terse documentation. Debugging your function f is a two-stage process. First, call mtrace(f) to store debugging information on f, and to overwrite f with a debug-ready version that will call the debugger itself. Second, do whatever you normally do at the command prompt to invoke f. This is often a direct call to f, but can be any command that eventually results in f being invoked. [The third, fourth, etc. stages, in which you actually fix the problem, are not covered here!] When f is invoked, a window will appear at the bottom of the screen, showing the code of f with a highlight on the first numbered line. (There is also an asterisk in the far left hand column of the same row, showing that there's a breakpoint.) The command prompt in R{} will change to "D(...

Arguments

code

ANY#ANY} method. (If only one argument was used for dispatching, there wouldn't be a hash symbol.) The following magic formula will do it: mtrace( 'ANY#ANY', from=environment( scrungepack:::scrunge)$.AllMTable) Then you can proceed as usual. Note that the method that is first dispatched may end up dispatching other methods-- you will have to work out which yourself, and mtrace them accordingly. You can mtrace various functions in the methods package, e.g. callGeneric, which might help you track down what's going on. In short: good luck! } section{Special functions}{ Certain system functions with "code" arguments are handled specially in step-mode: currently code{try}, code{suppressWarnings}, code{eval}, code{evalq}, code{with}, and code{within}. In step-mode only, your code argument in these is stepped-into by default if it is more than a simple statement, using a new code window. In go-mode, and in step-mode if the default behaviour has been changed, these functions are handled entirely by R{}. Hence, if you are in go-mode and an error occurs in one of these statements, the debugger will stop at the code{with} etc. statement, not inside it; but you can then step inside by pressing . The step-into-in-step-mode behaviour can be controlled globally using code{step.into.sysfuns}. To avoid step-in at a specific line, you can also just use code{go} to proceed to the following statement; this can be much faster than first stepping-in and then calling code{go}, because R{} itself handles the evaluation. To mimic the true behaviour of code{try}, the debugger should really just return a code{"try-error"} object if there is an error. However, that is probably not what you want when debugging. Instead, the debugger just behaves as usual with errors, i.e. it breaks into step-mode. If you do then want code{try} to return the code{try-error}, just as it would if you weren't debugging, type return( last.try.error()). Note that the code window for with, eval, etc. contains an on-exit block, just like normal debugger code windows. Its main use is probably to let you set a breakpoint-on-return. However, it seems that you can successfully put on.exit statements inside your eval etc. call, whether debugging or not. with and within are S3 generics, and the debug package only knows how to deal with the standard methods: currently with.default, within.data.frame, and within.list. You can debug specific methods manually, e.g. via mtrace( with.myS3class). within is more complicated than the others, and two extra code windows are currently used: one for the code of within itself, and one for your statement. The operation of within itself is not usually very interesting, so the debugger does not pause except at the end of it, unless there is an error. Errors can occur during the updating of your object, which happens after your expression has been evaluated, e.g. from within( data.frame(), bad <- quote( symbols.not.allowed))

itemize

  • useskipto move to the start of the exit code;
  • then usego(n)to run to the final NULL in the exit code;
  • then useqqq()to finish debugging.

pkg

mvbutils

Methods

S3 methods work fine with mtrace; just do e.g. mtrace( print.classofthing). Unsurprisingly, S4 methods are much more painful to work with. I've only done it once; the following approach worked in R{} 2.12, but probably isn't optimal. Suppose you have figured out that the offending call is something like scrunge( x, y, z), where scrunge is the name of an S4 generic; e.g. you may have tried mtrace( scrunge), and found yourself with a debug window containing a 1-line function standardGeneric("scrunge"). First, use findFunction( "scrunge") to work out which package contains the definition of scrunge-- say it's in package scrungepack. Next, you need to work out which specific scrunge method will be dispatched by scrunge( x, y, z). Try this: selectMethod( "scrunge", signature=character()) # Look for the 'attr(,"target")' line; it might be e.g. # attr(,"target") # x y # "ANY" "ANY" Now you know that it's the x and y args that will direct traffic (it could have been just x, or just z, or...

preformatted

selectMethod( "scrunge", sig=c( "matrix", "character"))

Options

As of version 1.2.0, output is sent by default to stderr(); this means that you get to see the step-mode output even if the debuggee is redirecting "real" output (e.g. via sink). If you don't like this (and I believe Tinn-R doesn't), set options( debug.catfile="stdout"). Command recall is ON by default, but this means that anything typed while debugging will also be seen in history() after leaving the debugger. If this is a problem, set options( debug.command.recall=FALSE). There are two adjustable limits on what gets printed out in step mode (otherwise, your screen will often fill with junk, and displaying results may take several minutes). First, printing will be aborted if it takes longer than getOption( "debug.print.time.limit") seconds, which by default is 0.5 seconds. You might need to increase that, e.g. for displaying big help files in the browser. Also, setting a finite time limit cutoff overrides any other time limits that have been set with setTimeLimit; this can be prevented by setting options( debug.print.time.limit=Inf). Second, by default only objects with object.size < 8192 bytes will be printed in full; for larger objects, a summary is given instead. You can force printing of any individual object via print, but you can also increase (or decrease) the threshold to X bytes, by setting options( threshold.debug.autoprint.size=X). The object.size test isn't foolproof, as some minuscule objects occupy hectares of screen real estate and take ages to print, whereas some big objects print compactly and fast. In my own work, I set the "threshold.debug.autoprint.size" option to Inf and the time limit usually to 0.5 seconds. Various TCL/TK-related aspects of the code window can be altered:
  • tab.widthdefaults to 4, for indenting code lines (not related to TCL/TK)
  • debug.fontdefaults to "Courier"; try e.g. ="Courier 24 italic"
  • debug.height(in lines) defaults to 10
  • debug.width(in characters) defaults to 120
  • debug.screen.posdefaults to "+5-5" for BL corner; try "-5-5" for BR, "-5+5" for TR, "+5+5" for TL.
  • debug.fgis foreground text colour, defaulting toblack

See Also

mtrace, go, skip, qqq, bp, get.retval, mtrace.off, check.for.tracees, step.into.sysfuns, last.try.error