In R, I want to create a function that return Flag=0 if it encounters any error:
Error<-function(x){
tryCatch(x,
error=function(e{
Flag=0
}
)
}
When I enter: Error(5+b). It does not reflect Flag=0.
Flag <- 1
tryCatch(
5+b,
error=function(e) { Flag <<- 0}
)
Flag
[1] 0
In your code, the scope of Flag is local to the error handler. Using <<- makes the assignment in the global environment.
You can return a string ('error') here if error occurs and check it's value to return 1/0.
Error<-function(x){
y <- tryCatch(x,error=function(e) return('error'))
as.integer(y != 'error')
}
Error(sqrt('a'))
#[1] 0
Error(sqrt(64))
#[1] 1
Related
It is clearly that the documentation of R clearly goes against having a break line between "}" and "else". However, it is odd that the first piece of codes works but the second one does not work (syntax error)
First program
x = 1
stupid_function = function(x){
if(x != 1){
print("haha")
}
else if( x == 1){
print("hihi")
}
}
stupid_function(x)
[1] "hihi"
Second program
x = 1
if(x != 1){
print("haha")
}
else if( x == 1){
print("hihi")
}
Error in source("~/.active-rstudio-document", echo = TRUE) :
~/.active-rstudio-document:6:3: unexpected 'else'
5: }
6: else
In the second program it sees a line at a time as it is typed in so at the point that the line with the } is typed in it cannot know that there will be further lines with an else so it assumes the statement is finished.
In the first case it can see all the code before it is run because it can see all the code in the function so it knows that the } has not finished the statement.
This line of argument works for an if/else but does not work in general. For example, this will produce an error when the function is
defined.
f <- function(x) {
x
* 2
}
Note that the if else need not be in a function for it to work. It just need to be in a continuous form or in a way to be expressed as a continuous block of code. One way is being in a function. The other is to write it in one line, or even ensure that there is no line break between the if block and the else block:
x <- 1
if(x != 1) print('haha') else print('hihi')
[1] "hihi"
More blocks of statements:
x <- 1
if(x != 1){
print("haha")
} else if( x == 1){ # Note how else begins immediatley after }
print("hihi")
}
[1] "hihi"
Note that you need to know when to put the line breaks whether in a function or outside of a function. Otherwise the code might fail or even give incorrect results.
Using subtraction:
x <- 1
x -
2
[1] -1
x <- 1
x
- 2
[1] -2
You need to know when/where to have the line breaks. Its always safe to have else follow the closing brace } of the previous if statement. ie:
if(...){
....
} else if(...){
....
} else {
...
}
I'm trying to use multiple actions in if statement. For example:
x <- 1
if (x == 1) {
paste("First")
1*1 #multiple actions
} else if (x == 2) {
paste("Second")
2*2 } else {("Nothing")
}
[1] 1 #what I'm getting
[2] "First"
1 #what I want to get
In this case only the second part of the expressions was printed to the console.
Any ideas how can I run all actions between if and else if ?
All statements are running as intended. The value of a statement is only printed to the console if all these conditions are true:
The value isn't saved to a variable
The value isn't invisible
It's the result of the last statement in an expression
R is running in interactive mode
The reason things sometimes print is to help people interactively exploring data in the command line. Instead of type print(x), they can save a few keystrokes by just typing x. In summary, use print if you want to be sure it's printed:
x <- 1
if (x == 1) {
print("First")
print(1*1)
} else if (x == 2) {
print("Second")
print(2*2)
} else {
invisible("Nothing")
}
# [1] "First"
# [1] 1
You can use print or cat:
getResult <- function(x = 1) {
if (x == 1) {
cat("First", 1 * 1, "\n")
} else if (x == 2) {
print("Second")
print(2 * 2)
} else {
cat("Nothing\n")
}
}
getResult()
# First 1
getResult(2)
# [1] "Second"
# [1] 4
This line of code returns TRUE if the file exits or NA if the directory does not exist.
In this case the directory does not exist so this line returns
file.info("M:/T/2014/")[1,"isdir"]
[1] NA
Now I want to catch this case so I do:
if(file.info("M:/T/2014")[1,"isdir"] != TRUE){
print("there is no directory")
}
But I get an error:
Error in if (file.info("M:/T/2014")[1, "isdir"] != TRUE) { :
missing value where TRUE/FALSE needed
I also tried:
if(as.character(file.info("M:/T/2014")[1,"isdir"]) == "NA"){
print("there is no directory")
}
Can you advise what to do to put != TRUE or == "NA" in the if statement?
Thank you.
Try something like this using an is.na statement:
f <- file.info("M:/T/2014/")[1,"isdir"]
if(!is.na(f) && !f) print("there is no directory")
Perhaps, though, you want:
f <- file.info("M:/T/2014/")[1,"isdir"]
if(is.na(f) | !f) print("there is no directory")
Is it possible in R to do the following:
execute cmd1
if cmd1 generates error, proceed to:
execute cmd2
Thanks
try and/or tryCatch may be of use to you. Consider the super-simple toy example below:
# Our function just returns it's input as long as input is not negative otherwise an error is generated
f <- function(n) {
if( n < 0 )
stop("need positive integer")
return(n)
}
# Our alternative function to run if we get an error from the first function
f2 <- function(n) return( cat( paste( "You have a negative number which is" , n ) ) )
# Now we try to run it with `try`:
if( class( try( f(-1) , silent = TRUE ) ) == "try-error" )
f2(-1)
#You have a negative number which is -1
# And using the sophisticated `tryCatch()`
tryCatch( f(-1) , finally = f2(-1) )
#Error in f(-1) : need positive integer
#You have a negative number which is -1
The return value of try() is the value of the expression if it evaluates without error, otherwise an object of the class "try-error". In the first example we just check to see if an error was generated using comparing the class of the return value of try and execute f2() if an error was generated.
Note there are quite a few ways to handle this and I certainly wouldn't advocate either of these as being the best, but they should be a useful starting point for you to learn more about error handling.
Try this, err is the error message in the try block.
tryCatch(stop(),
error=function(err){
print(1)
print(err)
})
Depending on your use case, even simple short-circuiting of boolean operators might be enough. i.e., if your functions can return TRUE to indicate no-error and FALSE to indicate an error, then you can use the fact that || will only evaluate the RHS operand if the LHS operand evaluates to FALSE.
> doAwesomeStuff <- function() {cat("OMG, I'm awesome! <falls flat on face>\n"); FALSE}
> okDoNormalStuff <- function() {cat("OMG, I'm OK! :-)\n"); TRUE}
> doAwesomeStuff() || okDoNormalStuff()
OMG, I'm awesome! <falls flat on face>
OMG, I'm OK! :-)
[1] TRUE
But if doAwesomeStuff() works,
> doAwesomeStuff <- function() {cat("OMG, I'm awesome!\n"); TRUE}
> doAwesomeStuff() || okDoNormalStuff()
OMG, I'm awesome!
[1] TRUE
I'm aware of the function on.exit in R, which is great. It runs the expression when the calling function exits, either normally or as the result of an error.
What I'd like is for the expression only to be run if the calling function returns normally, but not in the case of an error. I have multiple points where the function could return normally, and multiple points where it could fail. Is there a way to do this?
myfunction = function() {
...
on.exit( if (just exited normally without error) <something> )
...
if (...) then return( point 1 )
...
if (...) then return( point 2 )
...
if (...) then return( point 3 )
...
return ( point 4 )
}
The whole point of on.exit() is exactly to be run regardless of the exit status. Hence it disregards any error signal. This is afaik equivalent to the finally statement of the tryCatch function.
If you want to run code only on normal exit, simply put it at the end of your code. Yes, you'll have to restructure it a bit using else statements and by creating only 1 exit point, but that's considered good coding practice by some.
Using your example, that would be:
myfunction = function() {
...
if (...) then out <- point 1
...
else if (...) then out <- point 2
...
else if (...) then out <- point 3
...
else out <- point 4
WhateverNeedsToRunBeforeReturning
return(out)
}
Or see the answer of Charles for a nice implementation of this idea using local().
If you insist on using on.exit(), you can gamble on the working of the traceback mechanism to do something like this :
test <- function(x){
x + 12
}
myFun <- function(y){
on.exit({
err <- if( exists(".Traceback")){
nt <- length(.Traceback)
.Traceback[[nt]] == sys.calls()[[1]]
} else {FALSE}
if(!err) print("test")
})
test(y)
}
.Traceback contains the last call stack resulting in an error. You have to check whether the top call in that stack is equal to the current call, and in that case your call very likely threw the last error. So based on that condition you can try to hack yourself a solution I'd never use myself.
Just wrap the args of all your return function calls with the code that you want done. So your example becomes:
foo = function(thing){do something; return(thing)}
myfunction = function() {
...
if (...) then return( foo(point 1) )
...
if (...) then return( foo(point 2) )
...
if (...) then return( foo(point 3) )
...
return ( foo(point 4) )
}
Or just make each then clause into two statements. Using on.exit to lever some code into a number of places is going to cause spooky action-at-a-distance problems and make the baby Dijkstra cry (read Dijkstra's "GOTO considered harmful" paper).
Bit more readable version of my comment on #Joris' answer:
f = function() {
ret = local({
myvar = 42
if (runif(1) < 0.5)
return(2)
stop('oh noes')
}, environment())
# code to run on success...
print(sprintf('myvar is %d', myvar))
ret
}
I guess there is not a clean way yet. I usually create an OK variable at the beginning as FALSE and turn it to TRUE at the end. I prefer on.exit over isolating all my code into a tryCatch.
myfun = function() {
OK=F # the flag "OK" will be FALSE until the function ends OK
conn = my.db.connection.function()
dbBegin(conn)
on.exit({
if(OK) dbCommit(conn) else dbRollback(conn)
dbDisconnect(conn)
})
# ... Your code. You can edit database as a transaction.
# if anything fails in R or in the database a rollback will occur
OK=T # only if the code came to the end everything went ok, so we set the flag OK as TRUE
return(NULL)
}