I am debugging a function in R using browser() and have encountered something that I don't understand. Below is a simple example function:
testf<-function(x)
{
if(x==1) x=x+1
return(x)
}
If I run this it behaves as expected:
> testf(1)
[1] 2
> testf(2)
[1] 2
Now, I insert a browser() function to enter debug mode:
testf<-function(x)
{
browser()
if(x==1) x=x+1
return(x)
}
If I now run testf(1) and use the Next command feature in debug mode to step through the function, it produces the expected output of 2. However, if I run the if statement directly (e.g. by highlighting and pushing the Run button), x does not get incremented:
Browse[1]> x
[1] 1
Browse[1]> if(x==1) x=x+1
debug at #3: x = x + 1
Browse[3]> x
[1] 1
If I instead run x=x+1 by itself then x does get incremented:
Browse[3]> x
[1] 1
Browse[3]> x=x+1
Browse[3]> x
[1] 2
Browse[3]>
Then x does get incremented as expected.
Why? My understanding of debug mode is that you can run any command and it will get executed as if you were running the function, but this seems not to be the case with the if statement above.
What am I missing here?
The if condition works in two separate steps :
evaluate condition
execute statement
Perhaps easier to visualize what happens this way:
testf <- function(x)
{
browser()
if(x==1) {
x=x+1
}
return(x)
}
I am going to provide a more detailed answer to my question, based on Waldi's answer above. The real heart of my question is this: Why does my if statement perform differently in normal and debug modes?
> x=1
> if(x==1) x=x+1
> x
[1] 2
> testf(1)
Called from: testf(1)
Browse[1]> x
[1] 1
Browse[1]> if(x==1) x=x+1
debug at #3: x = x + 1
Browse[3]> x
[1] 1
The answer can be seen by using the debugger to step through the function. When I use the Next tool to step through the if, it takes two steps to get through rather than the one step that we might expect. This is because the if involves two steps:
Evaluate condition
Execute command.
Normally, these are executed together at one time. However, the debugger separates them. This is presumably because it is possible that an error could be in either the evaluation step or the execution step. This is sensible, but it has the side effect that if I run the if at the command line in debug mode, it only executes the first part (evaluate) and not the second part (execute).
Related
while debugging in the R language, is it possible to bypass the stop() and make it to the code that i want to step through?
myfun <-
function(){
browser()
stop("any way around this?")
print("code that i want to step through")
TRUE
}
myfun()
You can mask stop:
> myfun()
Called from: myfun()
Browse[1]> stop <- message
Browse[1]> n
debug at #4: stop("any way around this?")
Browse[2]> n
any way around this?
debug at #6: print("code that i want to step through")
Browse[2]> stop <- base::stop
Browse[2]> n
[1] "code that i want to step through"
debug at #8: [1] TRUE
Browse[2]> n
[1] TRUE
You can use the archived debug package. It contains a skip function you can use while debugging, though you are using another debug function then.
#devtools::install_version("debug",version="1.3.1")
library(debug)
mtrace(myfun)
myfun <-
function(){
print(1)
stop("any way around this?")
print(2)
print("code that i want to step through")
TRUE
}
myfun()
you can use then the debugger in console with skip(). For introduction of the debug package, check the documentation
I have the following code in the script test.R:
if (x==2){
stop("the script ends")
}
Now I source this script
source(test.R)
t <- 2
I would like the code to stop if x==2 and does not go further. However, it continues and assigns t <- 2. I can use the function warnings(options) but I want to avoid this option and implement a condition within the if. Any suggestion?
The code you list should work as expected.
As an example, I made two scripts, test.R and test2.R:
1. File test.R:
if (identical(x, 2)) {
stop("the script ends")
}
(Note: I'm using identical(x, 2) as the safer way to check whether x equals 2, but x == 2 would work the same in this example.)
2. File test2.R:
x <- 1
source("test.R")
t <- 1
print("This should be printed.")
x <- 2
source("test.R")
t <- 2
print("This should not be printed!")
Now I run test2.R from the console:
> t <- 5
> source('test2.R')
[1] "This should be printed."
Error in eval(ei, envir) : the script ends
> t
[1] 1
We see that the check passed the first time, when x == 1, and it failed the second time, when x == 2. Therefore, the value of t at the end is 1, because the first assignment was run and the second was not.
A while loop can create a condition that you can escape from as you are suggesting:
while (TRUE){
if (x==2) {
break
}
}
This is assuming that your code is 'all the way to the left' when executing. Seeing a little more might help, or better understanding how x is being set or being used. Note that using something like while(TRUE) might not be best practice, and can lead to infinite execution if you do not exit properly.
I want to test a function that can throw an error but I also want to ensure that a variable value is correct (to verify the expected last state before the error - so I want to test for unwanted side effects). Is it possible to do this?
Simplified expression to be tested
x <- 1 # could also be made "global" by "<<-"
stop("damn, an error occured")
How can I do something like
testthat("double check",
expect_error_and_TRUE( x == 1, {
x <- 1
stop("damn, an error occured")
}))
I could not find a way to "stack" (pipe) the expect functions?
If a function returns a value it doesn't throws an error and otherwise round. You can test for a specific string in expect_error if you wish, so you could set in the error the value of x.
{
x <- 1
stop("damn, an error occured")
}
## Error: damn, an error occured
x
## [1] 1
rm(x)
f <- function(){
x <- 1
stop("damn, an error occured")
}
f() == 1
## Error in f() : damn, an error occured
expect_error(f(), "damn, an error occured")
f <- function(){
x <- 1
stop("damn, an error occured, x is ", x)
}
expect_error(f(), "x is 1")
I would advise against testing code outside a function, as it depends on the environment, where it is run, so if you run it in the testing file it might not be the same as in the "main" part of your code
Here is a better example now to test for an unwanted side effect - and a simple solution:
library(testthat)
counter <- 1
test_that("error occurs but does not change the previous value", {
expect_error(if (log("a") == 42) counter <- counter + 1)
expect_equal(counter, 1)
})
I use data checks in my code, for example the following one:
if (...)
stop(paste('Warning: Weights do not sum up to 1')
The problem is that if the condition is true and the warning appears in the console, the code does not stop running. If hidden in a long code, one needs to scroll up always in the console output to see if a warning appeared.
Is there a way to tell R to interupt ALL code when the stop warning appears and the condition is true? Something like BREAK ?
I do not represent a reproducible example here because my code is quite long.
EDIT:
Here is a mini example:
When I execute
a=1+2
if (a==3)
stop('a equals 3')
b=4
1+1
I would like to stop after printing
> a=1+2
>
> if (a==3)
+ stop('a equals 3')
Error: a equals 3
but R executes everything, also the last part:
> a=1+2
>
> if (a==3)
+ stop('a equals 3')
Error: a equals 3
>
>
> b=4
>
> 1+1
[1] 2
According to stop, it only stops evaluation of the current expression. While I agree with Roland's comment to encapsulate your code into meaningful pieces via functions, a quick hack would be to wrap all your current code in curly braces. That will make it appear to the R parser as a single expression.
R> # without curly braces
R> x <- 1
R> y <- 2
R> if (x < y)
+ stop("x < y")
Error: x < y
R> print("hello")
[1] "hello"
R>
R> # with curly braces
R> {
+ x <- 1
+ y <- 2
+ if (x < y)
+ stop("x < y")
+ print("hello")
+ }
Error: x < y
If I understand you correctly, it seems not to be the default behaviour of R.
So I think there is some change of the stop handler. You can try to call options(stop=NULL) before running your code. See the doc:
The default behaviour (the NULL error-handler) in interactive use is
to return to the top level prompt or the top level browser, and in
non-interactive use to (effectively) call q("no", status = 1, runLast
= FALSE).
At least the following code worked in my case (R 3.2.1):
funErr <- function() {
if (TRUE)
stop("now")
print("after stop")
}
funCaller <- function() {
print("before call")
funErr()
print("after call")
}
print("before global")
# Also possible to uncomment the following to test the `stop()`
# inside of `funErr()`
if(TRUE)
stop("global error")
funCaller()
For some reason, when the body of my function is inside a with() expression, the debug mode doesn't seem to let me step inside the with() part. Why is that, and is there a way around this issue? Below is a silly (but hopefully reproducible) demo.
ff=function(x){
print("Hello")
with(iris,{
y=x;
z=y+mean(Sepal.Width);
return(z);})
}
Now enter debug mode and tryout the function...
debugonce(ff);debugonce(with);
ff(10)
Debug mode simply skips over the with() clause, and returns the answer (13.05733). How do I step INTO those inner clauses?
This works, it's just that what you expect it to do is not what it does. debug will look inside the with code, not inside the code you passed as an argument. Look closely:
> ff(10)
debugging in: ff(10)
debug at #1: {
print("Hello")
with(iris, {
y = x
z = y + mean(Sepal.Width)
return(z)
})
}
Browse[2]> n
debug at #2: print("Hello")
Browse[2]> n
[1] "Hello"
debug at #3: with(iris, {
y = x
z = y + mean(Sepal.Width)
return(z)
})
Browse[2]> n
Now look what's happening here, we are debugging in with:
debugging in: with(iris, {
y = x
z = y + mean(Sepal.Width)
return(z)
})
And this is the key:
debug: UseMethod("with")
Browse[3]> n
[1] 13.05733
What happened? Look at the with code:
> with
function (data, expr, ...)
UseMethod("with")
<bytecode: 0x00000000092f0e50>
<environment: namespace:base>
So as you can see, we did debug the single line in with. You can also debug with.default if you want to see what's happening in with in more detail, but I doubt that will do what you want. I don't know how to do that indirectly (even if you could debug {, which I don't think you can, that wouldn't help as you would be looking at the code for {, not the argument to {, same as with with), but as a hack you can use browse():
ff=function(x){
print("Hello")
with(iris,{
browser() # <<<--- this will allow you to browse inside the expression
y=x;
z=y+mean(Sepal.Width);
return(z);})
}