How to target exception-handling to specific exceptions? - r

Does R provide any support for targetting exception handling to only specific exceptions?
In Python, for example, one can narrow down exception-handling to specific exception types; e.g.:
try:
return frobozz[i]
except IndexError:
return DEFAULT
In this example, the exception handling will kick in only if i is an integer such that i >= len(frobozz) or i < -len(frobozz), but will not catch the exception resulting from, e.g., the case where i is the string "0" (which would be a TypeError, rather than an IndexError).

Wellllll...yes and no, and mostly no.
Every Python exception is wrapped in a particular error class which derives from Error, and Python modules are supposed to raise the "right" kinds of errors. For instance, an index out of range error should throw IndexError. The base language knows about these errors and so you can catch the appropriate error type in your except... clause.
R doesn't do that. Errors are untyped; there's no essential difference between an index out of bounds error and any other error.
That said, you can cheat under certain, very limited, circumstances.
> y <- tryCatch(x[[2]], error = function(e) e)
> y
<simpleError in x[[2]]: subscript out of bounds>
> y$message
[1] "subscript out of bounds"
The key here is the use of the tryCatch function and the error clause. The error clause in a tryCatch is a function of one variable which can perform arbitrary operations on e, which is an object of type 'simpleError' and contains an item named "message". You can parse message and handle interesting cases separately
> y <- tryCatch(x[[2]],
error = function(e) {
if ('subscript out of bounds' == e$message) return(NA) else stop(e))
})
> y
[1] NA
This only works if you can actually detect the error string you want to look for, and that isn't guaranteed. (Then again, it also isn't guaranteed in Python, so things aren't really much different from one another.)
Final question, though: why in Heaven's name are you doing this? What are you really trying to do?

Related

Making a throwable response to exception handling in R

I've turned my hand to R after many years of Java/C++. I am struggling to protect my operational flow using exception handling. Perhaps, I am looking at this with too much of a Java hat on.
Essentially, I am looking for a throw operator at the start of a function if a partiular argument to that function is incorrectly typed. An example for the structure (not functioning code) I am looking for:
myFunction <- function(someListArgument) {
if(class(someListArgument) != "List") {
throw(paste("Argument not a list: ", class(someListArgument)))
}
}
tryCatch({myFunction(c("whoops!"))},
error = function(cond) {},
....
)
I would really like the compartmentalisation of code as I am writing an R->MySQL DBMS API and I would like to keep well controlled and informative error reporting if incorrect datatypes are provided.

stopifnot() vs. assertError()

I wonder what the differences between stopifnot() and assertError() are:
assertError() is not found by default (You'll have to load the "tools" package first), but stopifnot() is.
More significantly, assertError() always throws an error message, even if I pass arguments like TRUE or FALSE, while stopifnot() does the obvious and expected thing.
Reading the manual page did not help. What is the correct use instead of assertError(length(x) != 7)? If x is undefined, the statement produces no error, but as soon as it is defined, it is producing errors, independent of the length of x (7 or not).
The main difference is where they should be used.
stopIfnot aim at stopping an execution if some conditions are not met during the run where assertError aim at testing your code.
assertError expect it's parameter to raise an error, this is what happens when x is not defined, there's an error
> length(x) != 7
Error: object 'x' not found
When you pass this expression to assertError, it raise an error and assertError return the conditions met (the error in itself). This allow you to test the failure cases of your code.
So assertError is mostly used in tests cases in a Test Driven Development pattern (TDD), when your code/function is supposed to raise an error for some specific parameters and ensure when you update your function later you're not breaking it.
Example usage of stopifnot and assertError:
mydiv <- function(a,b) {
stopifnot(b>0)
a/b
}
And now lets make a test to ensure this will raise an error if we pass "b" as 0:
tryCatch(
assertError(mydiv(3,0)),
error = function(e) { print("Warning, mydiv accept to divide by 0") }
)
Running this code produce no output, desired behavior.
Now if we comment the stopifnot in mydiv like this:
mydiv <- function(a,b) {
#stopifnot(abs(b)>0)
a/b
}
And testing again the tryCatch block, we get this output:
[1] "Warning, mydiv accept to divide by 0"
This is a small example of testing a function really throw an error as expected.
The tryCatch block is just to showcase with a different message, I hope this give more light on the subject.

R library not getting loaded when I try this using statConnector in R

I can access the basic function of stat library in R when I connect C# and R through statconnector. But if I load a library(), I am not able to call any of its function.
The code I am trying is:
rConn.SetSymbol("n1", 20);
rConn.Evaluate("library(dtw)");
rConn.Evaluate("x1<-rnorm(n1)");
rConn.Evaluate("x2<-rnorm(n1)");
rConn.Evaluate("Score<-dtw(x1,x2,keep.internals=TRUE)");
The error I get is when I run the last line i.e., rConn.Evaluate("Score<-dtw(x1,x2,keep.internals=TRUE)");
The error i get is -
There is no connection for this connection ID (Exception from HRESULT: 0x80040004 (OLE_E_NOCONNECTION))
You will find that with some functions called via StatConnector that you MUST use .EvaluateNoReturn instead of .Evaluate. It makes sense if you recognize that if you examine the class of "Score" (within R) via:
class(Score)
[1] "dtw"
You see that "Score" contains a dtw object. Implicitly whenever you use .Evaluate, you are calling a function with a return value. However, C# doesn't know what to do with a dtw object, so you get a funky error message that make you go hmmm. Try the equivalent of a void call instead:
rConn.EvaluateNoReturn("Score<-dtw(x1,x2,keep.internals=TRUE)");
And you should have no error executing dtw. To get a return value back into C#, while in R, take a look at names(Score) to see which variables are available, then something like
class(Score$normalizedDistance)
"numeric"
to get an idea how to cast the values for C#, as in:
double myDist = (double)rConn.Evaluate("Score$normalizedDistance");
Additional information I found that I received a similar error when calling 10+ concurrent statconnector instances.
The .Evaluate function when returning values would fail on 10% of calculations with the following error
There is no connection for this connection ID (Exception from HRESULT: 0x80040004 (OLE_E_NOCONNECTION))
at StatConnectorCommonLib.IStatConnector.Evaluate(String bstrExpression)
The fix I found to work was to store the result in a variable in R, and use the .EvaluateNoReturn and .GetSymbol to return the results.
StatConnector rConn = new StatConnector();
rConn.Init("R");
rConn.SetSymbol("n1", 20);
rConn.Evaluate ("x1<-rnorm(n1)");
var o = rConn.GetSymbol ("x1");
foreach (double d in o)
Console.WriteLine(d);
rConn.Close();
Check out the following article for my source and examples,
http://www.billbak.com/2010/11/accessing-r-from-clessons-learned/

Debugging unexpected errors in R -- how can I find where the error occurred?

Sometimes R throws me errors such as
Error in if (ncol(x) != 2) { : argument is of length zero
with no additional information, when I've written no such code. Is there a general way for finding which function in which package causes an error?
Since most packages come compressed, it isn't trivial to grep /usr/lib/R/library.
You can use traceback() to locate where the last error occurred. Usually it will point you to a call you make in your function. Then I typically put browser() at that point, run the function again and see what is going wrong.
For example, here are two functions:
f2 <- function(x)
{
if (x==1) "foo"
}
f <- function(x)
{
f2(x)
}
Note that f2() assumes an argument of length 1. We can misuse f:
> f(NULL)
Error in if (x == 1) "foo" : argument is of length zero
Now we can use traceback() to locate what went wrong:
> traceback()
2: f2(x) at #3
1: f(NULL)
The number means how deep we are in the nested functions. So we see that f calls f2 and that gives an error at line 3. Pretty clear. We could reassign f with browser placed just before the f2 call now to check it's input. browser() simply allows you to stop executing a function and look around in its environment. Similar to debug and debugonce except that you don't have to execute every line up until the point you know something goes wrong.
Just to add to what #SachaEpskamp has already suggested, setting options(error=recover) and options(show.error.locations=TRUE) can be extremely helpful when debugging unfamiliar code. The first causes R to launch a debugging session on error, giving you the option to invoke the browser at any point in the call stack up to that error. The second option will tell R to include the source line number in the error.

unitended reference comparision

I am getting this warning:
Possible unintended reference comparison; to get a value comparison, cast the left hand side to type 'string'
I tried this:
if (Convert.ToString(Session["message"]) == SESSIONTIMEOUT)
or
if (Session["message"].ToString() == SESSIONTIMEOUT)
But I'm still getting the above message.
You should use the Equals method for comparison of Strings, like this:
if (Session["message"].ToString().Equals(SESSIONTIMEOUT))
Generally speaking, the == operator is supposed to perform identity comparison - i.e., verifying that two object references point at the same object. See http://www.andymcm.com/csharpfaq.htm#6.7 for more information.
If you read the compiler warning message carefully, it says how you should solve it:
if ((string)Session["message"] == SESSIONTIMEOUT)
That's what casting the left hand side to string means, and this should be the solution. The reason why the message didn't go away, is that you didn't perform a complete rebuild (recompilation) of your project.
Now if there is any change the left hand side could be an object that's not a string, then use:
if (Session["message"] as string == SESSIONTIMEOUT)
but I guess you will not allow the type of your message to be non-string, so go for my first solution, the one suggested by the warning message.

Resources