Carl
Carl

Reputation: 5779

Issue with match.call

I wrote a function that uses match.call, and it works when I call the function directly, however, when the function is called within another function it breaks. I believe it has to do with how match.call handles environments, but I can't figure it out. Here is a reproducable example:

tester <- function() {

  var <- "helloworld"

  myFunc(var)

}


myFunc <- function(x) {

  tmp <- match.call()
  tmp[[1]] <- quote(toupper)
  eval(tmp)

}

tester() # error

myFunc("helloworld") # works fine

I believe that when myFunc is called within tester it can't find var because it exists in the isolated environment of the tester function.

Any ideas on how to get myFunc to work inside tester would be appreciated. I've tried changing the environment for eval and match.call, but to no avail.

Upvotes: 3

Views: 230

Answers (1)

Konrad Rudolph
Konrad Rudolph

Reputation: 545528

Your suspicion is exactly right.

The very simple solution is to evaluate the function in its parent’s context: replace eval with eval.parent.

myFunc <- function(x) {
  tmp <- match.call()
  tmp[[1]] <- quote(toupper)
  eval.parent(tmp)
}

Generally, the function traceback can help tremendously with debugging similar issues:

> tester()
Error in as.character(x) :
  cannot coerce type 'closure' to vector of type 'character'

Ok, but which “closure” (= function) are we talking about?

> traceback()
5: toupper(x = var)
4: eval(expr, envir, enclos)
3: eval(tmp) at #5
2: myFunc(var) at #5
1: tester()

The first line has the clue: toupper(x = var). In the context of tester, var refers to the function (closure) stats::var which is found because its package is attached.

Upvotes: 5

Related Questions