sebastian-c
sebastian-c

Reputation: 15395

What is the difference between finish and continue in browser()?

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.

Upvotes: 20

Views: 2750

Answers (3)

Technophobe01
Technophobe01

Reputation: 8676

Difference Between Browser and Continue

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:

  • Finish, or f: finishes execution of the current loop or function.
  • Continue, c: leaves interactive debugging and continues regular execution of the function. This is useful if you’ve fixed the bad state and want to check that the function proceeds correctly.

essentially, we talking about a subtlety in mode.

enter image description here

Browser / Recover Overview

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:

Upvotes: 3

takje
takje

Reputation: 2800

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/....
  • Because 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.

Upvotes: 9

Kelsey Abreu
Kelsey Abreu

Reputation: 1124

You can think of finish as a break in other languages. What happens is that you no longer care about the other items in the iteration because of a certain condition such as finding a specific item or an item that would cause an error.

continue, on the other hand, will stop at the current line of the loop, ignore the rest of the code block, and continue to the next item in the iteration. You would use this option if you intend to go through every item in the iteration and just ignore the items that satisfy the condition to skip over.

Upvotes: 0

Related Questions