Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the name of the calling function inside the called routine?

Tags:

r

Is there a "non-Internal" way to get the caller's name, as the function stop does?

The idea is that I have a small function that checks the inputs and halts execution if some condition is not met. This function is called by several others, that use the same validation code. If the input is invalid, the caller's environment is dumped (so I can see arguments passed to the function), and execution halts.

Simplified example:

check <- function(x) {     if(x<0)     {         print(as.list(parent.frame()))          evalq(stop("invalid input."), parent.frame())     } }  test <- function(x, y) {     check(x) } 

I thought that evaluating the expression quote(stop("blah")) in the caller's environment would make it show the caller's name. However, the result is the following:

test(-1, 2)  # $x # [1] -1 #  # $y # [1] 2 #  # Error in eval(substitute(expr), envir, enclos) : invalid input. 

And this doesn't change if I use parent.frame(n) with n>1 in evalq.

So here is the question, actually two questions: 1. Is there a way to get the name of the function that created an environment (assuming it was created as such)? 2. Why the workaround above fails?

EDIT: I said the workaround above fails because I wanted the error message to appear as

Error in test(x, y) : invalid input. 

as if the stop statement were a part of test body. So question 2 can be restated as: 2': Why didn't the evaluation of stop("invalid input.") capture the caller's name, considering it was evaluated in the environment of the caller?

like image 205
Ferdinand.kraft Avatar asked Mar 24 '13 05:03

Ferdinand.kraft


People also ask

What is the name of calling inside the function?

Calling a function inside of itself is called recursion. It's a technique used for many applications, like in printing out the fibonacci series.

How will you identify a calling function and a called function?

The calling function supplies the input (the actual arguments), which are then used by the called function to process the parameters because it has the definition, carry out the instructions, and return whatever that should be returned. The function that another function calls is known as the called function.


2 Answers

Thanks @GavinSimpson and @RicardoSporta, but I've figured it out. I'll post an answer in case somebody searches for this in SO.

The name of the function that generated the current call can be retrieved by

deparse(sys.calls()[[sys.nframe()-1]]) 

This returns a string that contains not only the name of the function, but the entire call object. The name alone can be retrieve by subsetting sys.calls()[[sys.nframe()-1]] before deparsing.

I wanted this because I wrote a function that checks the arguments and halts execution in case of an error. But I wanted this function to (i) dump the environment and (ii) show name of the function one level above in the execution stack. (i) is easy, but I was stuck in (ii).

As for the second question in my post, this is what happens: the expression stop("invalid input") is evaluated in the environment of the test function, but this is not the same thing as if the expression was part of test's body, because the execution stack is different in this 2 scenarios. In the latter case, stop has only test above it, but in the first, it has eval, check and then test upwards. The execution stack, returned by sys.calls() is not the same thing as the enclosing environments. This is what may cause confusion.

like image 146
Ferdinand.kraft Avatar answered Sep 28 '22 03:09

Ferdinand.kraft


See ?match.call. For example:

foo <- function() {   match.call()[[1]] }  foo()  as.character(foo()) 

which produces

> foo() foo >  > as.character(foo()) [1] "foo" 

A simplified version of your code is

check <- function(x) {   match.call()[[1]] }  test <- function(y) {   check(y) } 

giving

> test(2) check > as.character(test(2)) [1] "check" 

Note match.call() works via the use of sys.call() (actually it calls sys.call(sys.parent())) when called as I did above with no arguments. So you may wish to consult ?sys.call too.

like image 22
Gavin Simpson Avatar answered Sep 28 '22 03:09

Gavin Simpson