In the help file for browser
, there are two options that seem very similar:
f
finish execution of the current loop or function
c
exit the browser and continue execution at the next statement.
What is the difference between them and in what situations is the difference apparent?
Some clues about what may be the difference - I wrote a script called browse.R
with the following contents:
for (i in 1:2){
browser()
print(i)
}
This is the results of usingc
vs f
:
> source("browse.R")
Called from: eval(expr, envir, enclos)
Browse[1]> c
[1] 1
Called from: eval(expr, envir, enclos)
Browse[1]> c
[1] 2
> source("browse.R")
Called from: eval(expr, envir, enclos)
Browse[1]> f
[1] 1
Browse[2]> f
[1] 2
Note that the level of Browse[n]
changes. This still doesn't highlight any practical difference between them.
I also tried to see if perhaps things would disappear from the browser environment:
for (i in 1:2){
a <- "not modified"
browser()
print(a)
}
Called from: top level
Browse[1]> a <- "modified"
Browse[1]> f
[1] "modified"
Browse[1]> a
[1] "not modified"
Browse[1]> a <- "modified"
Browse[1]> c
[1] "modified"
So there's no difference there either.
For a web page that makes no requests after the page finishes loading, the Finish timer should stop shortly after the load timer. But for a web page that makes AJAX requests, the Finish timer will continue to run as the page continues to make requests after page load.
The Finish time in Chrome Devtools includes the asynchronously loading (non blocking) objects/elements on the page which may continue downloading way after the onLoad event for the page has fired.
The Finish timer, in contrast, measures the amount of time between when the page started loading and when the browser finished making its last request. It's a little more complicated than that but that's the general gist.
The Finish time, although technically also a response time, doesn't have as much end-user implication. In some cases, it seems that the Finish timer never stops but continues increasing, so it may not be the best assessment of web page response time. Show activity on this post.
There is a small difference.
c
immediately exits the browser (and debug mode) and after that executes the rest of the code in the normal way.f
on the contrary stays in the browser (and debug mode) while executing the rest of the function/loop. After the function/loop is finished, he also returns to the normal execution mode.Source: R-source (line 1105-1117) and R-help
This has a few implications:
c
closes the browser. This means that a new browser call is called from a function. Therefore you will see the line: Called from: function()
. f
on the other hand will not close the browser and therefore you will not see this line. The source code for this behavior is here: https://github.com/wch/r-source/....f
stays in the browser, f
also keeps track of the contextlevel: The browser prompt is of the form Browse[n]>: here var{n} indicates the ‘browser level’. The browser can be called when browsing (and often is when debug is in use), and each recursive call increases the number. (The actual number is the number of ‘contexts’ on the context stack: this is usually 2 for the outer level of browsing and 1 when examining dumps in debugger)
These differences can be tested with the code:
> test <- function(){
browser()
browser()
}
> test()
Called from: test()
Browse[1]> c
Called from: test()
Browse[1]> c
> test()
Called from: test()
Browse[1]> f
Browse[2]> f
As far as I see it, there is no practical difference between the two, unless there lies a practical purpose in the context stack. The debugging mode has no added value. The debug flag only opens the browser when you enter the function but since you are already inside the function, it will not trigger another effect.
At least for me, I feel the answer can be mapped out as a table, however, let's first frame up the usage of browser(), for those who may not yet have encountered it.
The browser
function is the basis for the majority of R debugging techniques. Essentially, a call to browser
halts execution and starts a special interactive session where you can inspect the current state of the computations and step through the code one command at a time.
Once in the browser, you can execute any R command. For example, one might view the local environment by using ls(); or choose to set new variables, or change the values assigned to variables simply by using the standard methods for assigning values to variables. The browser also understands a small set of commands specific to it. Which leads us to a discussion on Finish and continue...
The subtlety in relation to Finish and continue is that:
essentially, we talking about a subtlety in mode.
At least for me, you have to view this in the context of debugging a program written in R. Specifically, how you might apply Finish and continue. I am sure many understand this, but I include for completeness as I personally really didn't for a long time.
browser
allows you to look at the objects in the function in which the browser call is placed.recover
allows you to look at those objects as well as the objects in the caller of that function and all other active functions.
Liberal use of browser
, recover
, cat
and print
while you are writing functions allows your expectations and R's expectations to converge.
A very handy way of doing this is with trace. For example, if browsing at the end of the myFun function is convenient, then you can do:
trace(myFun, exit=quote(browser()))
You can customize the tracing with a command like:
trace(myFun, edit=TRUE)
If you run into an error, then debugging is the appropriate action. There are at least two approaches to debugging. The first approach is to look at the state of play at the point where the error occurs. Prepare for this by setting the error option. The two most likely choices are:
options(error=recover)
or
options(error=dump.frames)
The difference is that with recover
you are automatically thrown into debug
mode, but with dump.frames
you start debugging by executing:
debugger()
In either case you are presented with a selection of the frames (environments) of active functions to inspect.
You can force R to treat warnings as errors with the command:
options(warn=2)
If you want to set the error option in your .First
function, then you need a
trick since not everything is in place at the time that .First
is executed:
options(error=expression(recover()))
or
options(error=expression(dump.frames()))
The second idea for debugging is to step through a function as it executes. If you want to step through function myfun, then do:
debug(myfun)
and then execute a statement involving myfun. When you are done debugging, do:
undebug(myfun)
A more sophisticated version of this sort of debugging may be found in the debug package.
References:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With