1

I've read the other answers for issues related to the "promise already under evaluation" warning, but I am unable to see how they can help me avoid this problem.

Here I have a function that for one method, takes a default argument value that is a function of another value.

myfun <- function(x, ones = NULL) {
    UseMethod("myfun")
}


myfun.list <- function(x, ones = NA) {
    data.frame(x = x[[1]], ones)
}

ones <- function(x) {
    rep(1, length(x))
}

So far, so good:

myfun(list(letters[1:5]))
##   x ones
## 1 a   NA
## 2 b   NA
## 3 c   NA
## 4 d   NA
## 5 e   NA

But when I define another method that sets the default for the ones argument as the function ones(x), I get an error:

myfun.character <- function(x, ones = ones(x)) {
    myfun(as.list(x), ones)
}

myfun(letters[1:5])
## Error in data.frame(x = x[[1]], ones) : 
##  promise already under evaluation: recursive default argument reference or earlier problems? 

For various reasons, I need to keep the argument name the same as the function name (for ones). How can I force evaluation of the argument within my fun.character? I also need this to work (which it does):

myfun(letters[1:5], 1:5)
##   x ones
## 1 a    1
## 2 a    2
## 3 a    3
## 4 a    4
## 5 a    5

Thanks!

Ken Benoit
  • 14,454
  • 27
  • 50

1 Answers1

2

One would need to look deep into R's (notorious) environments to understand exactly, where it tries to find ones. The problem is located in the way supplied and default arguments are evaluated within a function. You can see this link from the R manual and also an explanation here.

The easy solution is to tell R where to look for it. It will save you the hassle. In your case that's the global environment.

Changing method myfun.character to tell it to look for ones in the global environment:

myfun.character <- function(x, ones = get('ones', envir = globalenv())(x)) {

  myfun(as.list(x), ones)

}

will be enough here.

Out:

myfun(letters[1:5])
#  x ones
#1 a    1
#2 a    1
#3 a    1
#4 a    1
#5 a    1

myfun(letters[1:5], 1:5)
#  x ones
#1 a    1
#2 a    2
#3 a    3
#4 a    4
#5 a    5
LyzandeR
  • 37,047
  • 12
  • 77
  • 87
  • That pointed me to a solution: for the package where this example represents the problem, to use the equivalent of `package::ones(x)` in the `myfun.character` function signature. Thanks! Just to shorten it, however, Is there any way to force evaluation of the package::ones(x) within myfun.character, using the original function signature from the question? – Ken Benoit Jul 26 '17 at 06:32
  • using `::` will point R to the package's namespace environment, so you are essentially telling R where to look at to find the function. Using `::` is the right way, I don't think there is a way to shorten it in this case. – LyzandeR Jul 26 '17 at 08:23