trace                  package:base                  R Documentation

Interactive Tracing and Debugging of Calls to a Function or Method

Description:

     A call to 'trace' allows you to insert debugging code (e.g., a
     call to 'browser' or 'recover') at chosen places in any function. 
     A call to 'untrace' cancels the tracing. Specified methods can be
     traced the same way, without tracing all calls to the function. 
     Trace code can be any R expression.  Tracing can be temporarily
     turned on or off globally by calling 'tracingState'.

Usage:

     trace(what, tracer, exit, at, print, signature,
           where = topenv(parent.frame()), edit = FALSE)
     untrace(what, signature = NULL, where = topenv(parent.frame()))

     tracingState(on = NULL)
     .doTrace(expr, msg)

Arguments:

    what: The name (quoted or not) of a function to be traced or
          untraced.  For 'untrace' or for 'trace' with more than one
          argument, more than one name can be given in the quoted form,
          and the same action will be applied to each one.

  tracer: Either a function or an unevaluated expression.  The function
          will be called or the expression will be evaluated either at
          the beginning of the call, or before those steps in the call
          specified by the argument 'at'. See the details section.

    exit: Either a function or an unevaluated expression.  The function
          will be called or the expression will be evaluated on exiting
          the function. See the details section.

      at: optional numeric vector.  If supplied, 'tracer' will be
          called just before the corresponding step in the body of the
          function. See the details section. 

   print: If 'TRUE' (as per default), a descriptive line is printed
          before any trace expression is evaluated.

signature: If this argument is supplied, it should be a signature for a
          method for function 'what'.  In this case, the method, and
          _not_ the function itself, is traced.

    edit: For complicated tracing, such as tracing within a loop inside
          the function, you will need to insert the desired calls by
          editing the body of the function.  If so, supply the 'edit'
          argument either as 'TRUE', or as the name of the editor you
          want to use.  Then 'trace()' will call 'edit' and use the
          version of the function after you edit it. See the details
          section for additional information. 

   where: where to look for the function to be traced; by default, the
          top-level environment of the call to 'trace'.

          An important use of this argument is to trace a function when
          it is called from a package with a name space.  The current
          name space mechanism imports the functions to be called (with
          the exception of functions in the base package).  The
          functions being called are _not_ the same objects seen from
          the top-level (in general, the imported packages may not even
          be attached).  Therefore, you must ensure that the correct
          versions are being traced.  The way to do this is to set
          argument 'where' to a function in the name space.  The
          tracing computations will then start looking in the
          environment of that function (which will be the name space of
          the corresponding package). (Yes, it's subtle, but the
          semantics here are central to how name spaces work in R.) 

      on: logical; a call to  the support function 'tracingState'
          returns 'TRUE' if tracing is globally turned on, 'FALSE'
          otherwise.  An argument of one or the other of those values
          sets the state.  If the tracing state is 'FALSE', none of the
          trace actions will actually occur (used, for example, by
          debugging functions to shut off tracing during debugging).

expr, msg: 

     { arguments to the support function '.doTrace', calls to which are
     inserted into the modified function or method: 'expr' is the
     tracing action (such as a call to 'browser()', and 'msg' is a
     string identifying the place where the trace action occurs. }

Details:

     The 'trace' function operates by constructing a revised version of
     the function (or of the method, if 'signature' is supplied), and
     assigning the new object back where the original was found. If
     only the 'what' argument is given, a line of trace printing is
     produced for each call to the function (back compatible with the
     earlier version of 'trace').

     The object constructed by 'trace' is from a class that extends
     '"function"' and which contains the original, untraced version. A
     call to 'untrace' re-assigns this version.

     If the argument 'tracer' or 'exit' is the name of a function, the
     tracing expression will be a call to that function, with no
     arguments.  This is the easiest and most common case, with the
     functions 'browser' and 'recover' the likeliest candidates; the
     former browses in the frame of the function being traced, and the
     latter allows browsing in any of the currently active calls.

     The 'tracer' or 'exit' argument can also be an unevaluated
     expression (such as returned by a call to 'quote' or
     'substitute').  This expression itself is inserted in the traced
     function, so it will typically involve arguments or local objects
     in the traced function.  An expression of this form is useful if
     you only want to interact when certain conditions apply (and in
     this case you probably want to supply 'print=FALSE' in the call to
     'trace' also).

     When the 'at' argument is supplied, it should be a vector of
     integers referring to the substeps of the body of the function
     (this only works if the body of the function is enclosed in '{
     ...}'.  In this case 'tracer' is _not_ called on entry, but
     instead just before evaluating each of the steps listed in 'at'. 
     (Hint: you don't want to try to count the steps in the printed
     version of a function; instead, look at 'as.list(body(f))' to get
     the numbers associated with the steps in function 'f'.)

     An intrinsic limitation in the 'exit' argument is that it won't
     work if the function itself uses 'on.exit', since the existing
     calls will override the one supplied by 'trace'.

     Tracing does not nest.  Any call to 'trace' replaces previously
     traced versions of that function or method (except for edited
     versions as discussed below), and 'untrace' always restores an
     untraced version.  (Allowing nested tracing has too many
     potentials for confusion and for accidentally leaving traced
     versions behind.)

     When the 'edit' argument is used repeatedly with no call to
     'untrace' on the same function or method in between, the
     previously edited version is retained. If you want to throw away
     all the previous tracing and then edit, call 'untrace' before the
     next call to 'trace'.  Editing may be combined with automatic
     tracing; just supply the other arguments such as 'tracer', and the
     'edit' argument as well.  The 'edit=TRUE' argument uses the
     default editor (see 'edit').

     Tracing primitive functions (builtins and specials) from the base
     package works, but only by a special mechanism and not very
     informatively.  Tracing a primitive causes the primitive to be
     replaced by a function with argument ... (only).  You can get a
     bit of information out, but not much.  A warning message is issued
     when 'trace' is used on a primitive.

     The practice of saving the traced version of the function back
     where the function came from means that tracing carries over from
     one session to another, _if_ the traced function is saved in the
     session image.  (In the next session, 'untrace' will remove the
     tracing.)  On the other hand, functions that were in a package,
     not in the global environment, are not saved in the image, so
     tracing expires with the session for such functions.

     Tracing a method is basically just like tracing a function, with
     the exception that the traced version is stored by a call to
     'setMethod' rather than by direct assignment, and so is the
     untraced version after a call to 'untrace'.

     The version of 'trace' described here is largely compatible with
     the version in S-Plus, although the two work by entirely different
     mechanisms.  The S-Plus 'trace' uses the session frame, with the
     result that tracing never carries over from one session to another
     (R does not have a session frame).  Another relevant distinction
     has nothing directly to do with 'trace':  The browser in S-Plus
     allows changes to be made to the frame being browsed, and the
     changes will persist after exiting the browser.  The R browser
     allows changes, but they disappear when the browser exits.  This
     may be relevant in that the S-Plus version allows you to
     experiment with code changes interactively, but the R version does
     not.  (A future revision may include a 'destructive' browser for
     R.)

Value:

     In the simple version (just the first argument), invisible 'NULL'.
     Otherwise, the traced function(s) name(s).  The relevant
     consequence is the assignment that takes place.

Note:

     The version of function tracing that includes any of the arguments
     except for the function name requires the 'methods' package
     (because it uses special classes of objects to store and restore
     versions of the traced functions).

     If methods dispatch is not currently on, 'trace' will load the
     methods name space, but will not put the methods package on the
     search list.

References:

     Becker, R. A., Chambers, J. M. and Wilks, A. R. (1988) _The New S
     Language_. Wadsworth & Brooks/Cole.

See Also:

     'browser' and 'recover', the likeliest tracing functions; also,
     'quote' and 'substitute' for constructing general expressions.

Examples:

     require(graphics)

     ##  Very simple use
     trace(sum)
     hist(stats::rnorm(100)) # shows about 3-4 calls to sum()
     untrace(sum)

     if(.isMethodsDispatchOn()) { # non-simple use needs 'methods' package

     f <- function(x, y) {
         y <- pmax(y, .001)
         x ^ y
     }

     ## arrange to call the browser on entering and exiting
     ## function f
     trace("f", browser, exit = browser)

     ## instead, conditionally assign some data, and then browse
     ## on exit, but only then.  Don't bother me otherwise

     trace("f", quote(if(any(y < 0)) yOrig <- y),
           exit = quote(if(exists("yOrig")) browser()),
           print = FALSE)

     ## trace a utility function, with recover so we
     ## can browse in the calling functions as well.

     trace("as.matrix", recover)

     ## turn off the tracing

     untrace(c("f", "as.matrix"))

     ## Not run: 
     ## trace calls to the function lm() that come from
     ## the nlme package.
     ## (The function nlme is in that package, and the package
     ## has a name space, so the where= argument must be used
     ## to get the right version of lm)

     trace(lm, exit = recover, where = nlme)
     ## End(Not run)
     }

