R warning() wrapper - raise to parent function - r

I have a wrapper around the in-built warning() function in R that basically calls warning(sprintf(...)):
warningf <- function(...)
warning(sprintf(...))
This is because I use warning(sprintf(...)) so often that I decided to make a function out of it (it's in a package I have of functions I use often).
I then use warningf when I write functions. i.e., instead of writing:
f <- function() {
# ... do stuff
warning(sprintf('I have %i bananas!',2))
# ... do stuff
}
I write:
f <- function() {
# ... do stuff
warningf('I have %i bananas!',2)
# ... do stuff
}
If I call the first f(), I get:
Warning message:
In f() : I have 2 bananas!
This is good - it tells me where the warning came from f() and what went wrong.
If I call the second f(), I get:
Warning message:
In warningf("I have %i bananas!",2) : I have 2 bananas!
This is not ideal - it tells me the warning was in the warningf function (of course, because it's the warningf function that calls warning, not f), masking the fact that it actually came from the f() function.
So my question is : Can I somehow "raise" the warning call so it displays the warning in f() message instead of the warning in warningf ?

One way of dealing with this is to get a list of the environments in your calling stack, and then pasting the name of the parent frame in your warning.
You do this with the function sys.call() which returns an item in the call stack. You want to extract the second from last element in this list, i.e. the parent to warningf:
warningf <- function(...){
parent.call <- sys.call(sys.nframe() - 1L)
warning(paste("In", deparse(parent.call), ":", sprintf(...)), call.=FALSE)
}
Now, if I run your function:
> f()
Warning message:
In f() : I have 2 bananas!
Later edit : deparse(parent.call) converts the call to a string in the case that the f() function had arguments, and shows the call as it was specified (ie including arguments etc).

I know it's old but, sys.call(sys.nframe() - 1L), or sys.call(-1),
returns a vector, with the function name and the argument.
If you use it inside paste() it will raise two warnings, one from the function and one from the argument.
The answer doesn't show because f() has no arguments.
sys.call(sys.nframe() - 1L)[1] does the trick.

Related

Limit the calls to an R function in case of warning

I have a function foo:
foo<-function(x,y,z){
{
some initial R code
}
eresult<-tryCatch(expr= eresult<-eclat(),
warning = function(w){
writelog(paste(w),logfile)
result<-eclat()
return(result)
},
error=function(e){
writelog(paste(e),logfile)
})
}
I am calling foo in loop using mapply over two columns of a data.frame df and one fixed argument "db_credential" for parameter z.
df<-data.frame(a=(1,2),b=c(2,3))
tryCatch(expr=mapply(FUN=foo,df$a,df$b,"db_credential"),
warning=function(w){writelog(paste(w),logfile)},
error=function(e){writelog(paste(e),logfile)})
On execution of this set of code, the eclat function throws a warning due to some choice of parameters for the function call of eclat. So foo is being called 4 times.
Is there a way by which I can restrict the call to foo only 2 times [to avoid the execution of "some initial R code" which involves fetching data from database and it's transformation] and yet handle all the warnings and errors.
I just want that the eclat function should be called again with the same parameters to produce the output rather than the control being thrown to the warning part of mapply call.

Why expression after return's parenthesis is checked for lexical correctness, but is not evaluated?

Consider the following code:
a = function() {
return (23)
}
b = function() {
return (23) * 23
}
c = function() {
return (23) * someUndefinedVariable
}
All of the above runs successfully (if called) and return 23.
I assumed that R ignores everything that goes after the closing parenthesis of return, but it does not really, because this code fails during code loading:
d = function() {
return (23) something
}
My assumption is that in the latter example some lexer or parser fails. But in the former, expression is parsed as (return(23))*some (because return is treated like a function), but evaluation stops at return and therefore R does not try to find some.
Does that sounds ok? Is that the reason? Is such behavior intended? Can I enable some warnings so that interpreter tells me about such 'unreachable code'?
The failure of this code:
d = function() {
return (23) something
}
... has nothing to do with the prior code and everything to do with the inability to parse: return (23) something. Unlike the earlier misguided attempt to redefine c which had a valid/parseable function body, the d-body is incapable of being put into a functional form. The parser doesn't really stop at return(23) but rather after it tokenizes something and "realizes" that it is not a semicolon or an infix function name. So the R interpreter now has two expressions and no valid connector/separator between them.
The referenced objects inside R function bodies at the time of definition do not get evaluated or even checked for existence in the parameter list or outside the function. (R is not a compiler.)
R parses the statement before it is evaluated:
parse(text = "funky <- function(x) {
return(x) * dog
}")
returns:
expression(funky <- function(x) {
return(x) * dog
})
However,
parse(text = "funky <- function(x) {
return(x) dog
}")
returns:
Error in parse(text = "funky <- function(x) {\n return(x) dog\n}") :
<text>:2:19: unexpected symbol
1: funky <- function(x) {
2: return(x) dog
^
In the above example, even though the variable dog doesn't exist (and comes after return), R is still able to parse it as it correct code.
return is not just "treated like a function", it is a function. And anytime it's called, the code path will exit from whatever function you're in at that moment.
So that means that by the time R would have gotten to multiplying the result of return by 23, it's all over, that evaluation stops, and there are no errors or warnings to report (just like there are no warnings or errors when you return inside some if condition).
Whereas your last function simply cannot be parsed (which more or less means that the expression is put into a function tree), and so that (function) object can't be created.

Resuming stopped evaluation in R with correct search path

I have a function within a loaded library that stops the evaluation on its arguments using the substitute function. This function then calls another within that same library, which calls another function from that library, and so forth, until several calls later when I want to evaluated that initial argument in the original environment in which it was provided. The problem I have is that the search path for functions in loaded libraries includes namespace::base before the global environment. For example, let's say that foo and bar are both functions in the library lib. As such, the environment in which they are defined is namespace::lib. Consider the following:
> require(lib)
> foo
function (x)
{
x <- substitute(x)
bar(x)
}
<environment: namespace:lib>
> bar
function (x)
{
eval(x)
}
<environment: namespace:lib>
> length = 2
> foo(length)
function (x) .Primitive("length")
Because bar is a function within a loaded library, it searches namespace::base first and finds the above. However, if bar was defined by the user in the interactive session, it would have returned 2. I am looking for a way to cause these functions to behave as if I never halted evaluation, in which case 2 would be returned regardless of the environment in which the functions are defined.
I can't simply use mget to evaluate length starting at .GlobalEnv because then the following would not work:
> baz = function()
+ {
+ length <- 3
+ foo(length)
+ }
> baz()
function (x) .Primitive("length")
I could instead add an extra argument to all involved functions that tracks how many frames ago the evaluation was halted. However, this is pretty messy and not ideal.
I could also call sys.function inside the last function, bar, and trace my way back through the previous calls and evaluate my argument in the environment above the function that halted the evaluation. For example, if I call sys.function(1) within the body of bar after calling foo(length) then I get the following:
function (x)
{
eval(x)
}
This is indeed identical to foo. I can then use eval with sys.frames. This seems more general but less than perfect. I would have to know which functions stop evaluation.
Does anyone have a more general solution?
Does adding a default enviroment to these function help with the problem?
lib<-new.env()
assign("foo", function(x, env=parent.frame()) {
x<-substitute(x);
bar(x, env)
}, envir=lib)
assign("bar", function(x, env=parent.frame()) {
eval(x, env)
}, envir=lib)
attach(lib)
length = 2
foo(length)
# [1] 2
baz <- function() {
length <- 3
foo(length)
}
baz()
# [1] 3
bar(expression(baz()))
# [1] 3
If not, perhaps you could make a clearer, reproducible example with function calls and your expected output. Otherwise it's unclear where you are having trouble.

"could not find function" when using functions as arguments

I have two .R files, plotDataSet(..) and plotAllDataSets(). plotDataSet(..) makes a call to curve(..) (in the R graphics library), while plotAllDataSets() makes a call to plotDataSet(..). plotDataSet(..) takes a function as a parameter, and passes it to curve(..).
I want to pass in my function argument for curve(..) into plotDataSet(..) from a list of functions, such as:
v <- c(function(x){x}, function(x){x*x}, function(x){x*x}, function(x){x*x*x},
function(x){x*x}, function(x){x*x*x}, function(x){x*x*x})
for (i in 1:7) {
plotSaveData(data, v[i], i)
}
I get the following output: Error in eval(expr, envir, enclos) :
could not find function "expectedOrderEquation".
Interestingly, when I call plotDataSet(..) and pass in a function like function(x){x*x}, it works fine:
for (i in 1:7) {
plotSaveData(data, function(x) {x}, i)
}
But this won't let me call plotSaveData(..) while cycling through a list of functions.
Can someone please explain why this does not work?
I hope this is sufficient, but I am happy to provide more context as needed. Also, I am a bit new to R, so any corrections to my descriptions would be helpful.
use double brackets instead of single brackets
v[[i]] instead of v[i]
Have a look at the difference between these two:
v[[i]] (3)
v[i] (3) # error
The single brackets returns a list, whose contents is a function
The double brackets returns the function.

Environment chaining in R

In my R development I need to wrap function primitives in proto objects so that a number of arguments can be automatically passed to the functions when the $perform() method of the object is invoked. The function invocation internally happens via do.call(). All is well, except when the function attempts to access variables from the closure within which it is defined. In that case, the function cannot resolve the names.
Here is the smallest example I have found that reproduces the behavior:
library(proto)
make_command <- function(operation) {
proto(
func = operation,
perform = function(., ...) {
func <- with(., func) # unbinds proto method
do.call(func, list(), envir=environment(operation))
}
)
}
test_case <- function() {
result <- 100
make_command(function() result)$perform()
}
# Will generate error:
# Error in function () : object 'result' not found
test_case()
I have a reproducible testthat test that also outputs a lot of diagnostic output. The diagnostic output has me stumped. By looking up the parent environment chain, my diagnostic code, which lives inside the function, finds and prints the very same variable the function fails to find. See this gist..
How can the environment for do.call be set up correctly?
This was the final answer after an offline discussion with the poster:
make_command <- function(operation) {
proto(perform = function(.) operation())
}
I think the issue here is clearer and easier to explore if you:
Replace the anonymous function within make_command() with a named one.
Make that function open a browser() (instead of trying to get result). That way you can look around to see where you are and what's going on.
Try this, which should clarify the cause of your problem:
test_case <- function() {
result <- 100
myFun <- function() browser()
make_command(myFun)$perform()
}
test_case()
## Then from within the browser:
#
parent.env(environment())
# <environment: 0x0d8de854>
# attr(,"class")
# [1] "proto" "environment"
get("result", parent.env(environment()))
# Error in get("result", parent.env(environment())) :
# object 'result' not found
#
parent.frame()
# <environment: 0x0d8ddfc0>
get("result", parent.frame()) ## (This works, so points towards a solution.)
# [1] 100
Here's the problem. Although you think you're evaluating myFun(), whose environment is the evaluation frame of test_case(), your call to do.call(func, ...) is really evaluating func(), whose environment is the proto environment within which it was defined. After looking for and not finding result in its own frame, the call to func() follows the rules of lexical scoping, and next looks in the proto environment. Neither it nor its parent environment contains an object named result, resulting in the error message you received.
If this doesn't immediately make sense, you can keep poking around within the browser. Here are a few further calls you might find helpful:
environment(get("myFun", parent.frame()))
ls(environment(get("myFun", parent.frame())))
environment(get("func", parent.env(environment())))
ls(environment(get("func", parent.env(environment()))))

Resources