Strange behavior of tidyverse: Jumping out of "browser()" mode


#1

I an running R 3.5.1 and just completed an extensive update of many of packages. In my shiny app, I have a program that uses tidyverse to calculate some sums. I am running this in browser mode to test out the code.
Here is the code:

 # extracting data
  browser()
  
  if(nchar(placefips) == 0) {  # Output for places
  sexbyage <- codemog_api(data="b01001",db=ACS, geonum=paste("1", state, ctyfips, sep=""), meta="no")
  }  else {
    sexbyage <- codemog_api(data="b01001",db=ACS, geonum=paste("1", state, placefips, sep=""), meta="no")
  }
  
  # Creating decades
  sexbyaged <- sexbyage %>%
    mutate( m0009 = B01001_003 + B01001_004,
            m1019 = B01001_005 + B01001_006 + B01001_007,
            m2029 = B01001_008 + B01001_009 + B01001_010 + B01001_011,
            m3034 = B01001_012 + B01001_013,
            m4049 = B01001_014 + B01001_015,
            m5059 = B01001_016 + B01001_017,
            m6069 = B01001_018 + B01001_019 + B01001_020 + B01001_021,
            m7079 = B01001_022 + B01001_023,
            m8000 = B01001_024 + B01001_025,
            f0009 = B01001_027 + B01001_028,
            f1019 = B01001_029 + B01001_030 +	B01001_031,
            f2029 = B01001_032 + B01001_033 +	B01001_034 + B01001_035,
            f3034 = B01001_036 + B01001_037,
            f4049 = B01001_038 + B01001_039,
            f5059 = B01001_040 + B01001_041,
            f6069 = B01001_042 + B01001_043 + B01001_044 + B01001_045,
            f7079 = B01001_046 + B01001_047,
            f8000 = B01001_048 + B01001_049)

When R (or R-Studio) executes this code, the program jumps out of browser mode and tries to complete the rest of the run.

Why is this happening?
TIA
AB


#2

Since this code isn’t runnable as-is, it would help to have a little more info — at which exact point does what you describe happen? (If you’re using RStudio: what is highlighted just before the step where the code suddenly runs the rest of the way through?) What are you expecting to have happen at that point, instead? Are you stepping, stepping-into, or stepping-over?

Using browser() does require mentally keeping track of the tree structure of your code to some extent, so that you know when to “step into” (or “step over”) vs simply “step”.


#3

Here is some background.
I am modifying a function in a shiny app. The function pulls data from an locally defined API and is going to create a population pyramid.

What is happening is that the program encounters the browser() command, it executes the API call:
sexbyage <- codemog_api(data="b01001",db=ACS, geonum=paste("1", state, ctyfips, sep=""), meta="no")
without a problem. Then it runs the tidyverse call:

sexbyaged <- sexbyage %>%
mutate(...)

At this point, the program exits the browser() mode, without my intervention, exits the function and then continues through the rest of the application until it encounters an "object not defined" error. This error occurs because the objects created by the function in question have not been created.

The tidyverse command does not return an error or a warning, so it's not clear to me what is going on.

I'm using
R version 3.5.1 (2018-07-02) -- "Feather Spray"
and
R Studio Version 1.1.456

on a Windows version 7 machine.


#4

Are there statements in your function after sexbyaged <- sexbyage %>% mutate(...)?

browser() doesn't quite work the way you maybe expect — it's not the same thing as setting a breakpoint from which you can step the rest of the way through all of your code statement-by-statement. browser() is meant to let you inspect and run code in the environment from which it is called — meaning, in this case, the function where you put the browser() statement. You can step down into functions within that environment (and you can call browser() again while you're already browsing), but it won't browse up into the parent environment of the one that called browser().

Here's a silly example to illustrate...
this_num <- 42

fun_outer <- function(x) {
  
  fun_inner <- function(y) {
    browser()
    z <- y * 2
    print(paste("Turn ", y, " into ", z))
    z
  }
  
  other_num <- fun_inner(x)
  
  print("it's over!")
  
  other_num
}

fun_outer(this_num)

print("the end!")

Running interactively line by line, I get this:

> fun_outer(this_num)
Called from: fun_inner(x)
Browse[1]> n
debug at #5: z <- y * 2
Browse[2]> n
debug at #6: print(paste("Turn ", y, " into ", z))
Browse[2]> n
[1] "Turn  42  into  84"
debug at #7: z
Browse[2]> n
[1] "it's over!"
[1] 84

When I'm on the last statement of fun_inner() and I choose Next ("evaluate the next statement, stepping over function calls"), we exit fun_inner() and execution proceeds until the end of fun_outer(). I wind up with my cursor right in front of print("it's over!").

If I'm source()ing, then everything after the end of fun_inner() executes as soon as I've stepped past the last statement in fun_inner():

> source('/cloud/project/browser_funs.R')
Called from: fun_inner(x)
Browse[1]> n
debug at /cloud/project/browser_funs.R#7: z <- y * 2
Browse[2]> n
debug at /cloud/project/browser_funs.R#8: print(paste("Turn ", y, " into ", z))
Browse[2]> n
[1] "Turn  42  into  84"
debug at /cloud/project/browser_funs.R#9: z
Browse[2]> n
[1] "it's over!"
[1] "the end!"

To work more within browser()'s paradigm, you might try running the code inside your function at the console while you're browsing, without stepping. So, when the browser starts, use Cmd/Ctrl-Enter to interactively run through the statements inside your function line-by-line (or type in new code directly at the console). This will not change what the current browse point is!


#5

Thanks @jcblum

I worked though this issue in a stub program and found multiple errors, including some incorrect variable names.

One thing that didn't happen in the main application was useful error reporting. For example, tidyverse didn't didn't report that a variable name was undefined, it just stopped and kicked me out. When I moved the code over to the stub program, the error was flagged and reported.

I suppose my issue is with the error reporting. Perhaps this is something the tidyverse developers can work on for the next release.

So it goes.


#6

The RStudio IDE has some diagnostic options which may fit your needs.
Tools > Global Options > Code > Diagnostics

Without having run your code, I don't think this has anything to do with the tidyverse - it's just the way R is designed.