Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using the same argument names for a function defined inside another function

Why does

f <- function(a) {
    g <- function(a=a) {
        return(a + 2)
    }
    return(g())
}
f(3)  # Error in a + 2: 'a' is missing

cause an error? It has something to do with the a=a argument, particularly with the fact that the variable names are the same. What exactly is going on?

Here are some similar pieces of code that work as expected:

f <- function(a) {
    g <- function(a) {
        return(a + 2)
    }
    return(g(a))
}
f(3)  # 5

f <- function(a) {
    g <- function(g_a=a) {
        return(g_a + 2)
    }
    return(g())
}
f(3)  # 5

g <- function(a) a + 2
f <- function(a) g(a)
f(3)  # 5
like image 207
Adrian Avatar asked Oct 27 '14 16:10

Adrian


2 Answers

The problem is that, as explained in the R language definition:

The default arguments to a function are evaluated in the evaluation frame of the function.

In your first code block, when you call g() without any arguments, it falls back on its default value of a, which is a. Evaluating that in the "frame of the function" (i.e. the environment created by the call to g()), it finds an argument whose name matches the symbol a, and its value is a. When it looks for the value of that a, it finds an argument whose name matches that symbol, and whose value is a. When...

As you can see, you're stuck in a loop, which is what the error message is trying to tell you:

Error in g() : 
  promise already under evaluation: recursive default argument reference or 
earlier problems?

Your second attempt, which calls g(a) works as you expected, because you've supplied an argument, and, as explained in the same section of R-lang:

The supplied arguments to a function are evaluated in the evaluation frame of the calling function.

There it finds a symbol a, which is bound to whatever value you passed in to the outer function's formal argument a, and all is well.

like image 163
Josh O'Brien Avatar answered Oct 08 '22 11:10

Josh O'Brien


The problem is the a=a part. An argument can't be its own default. That is a circular reference.

This example may help clarify how it works:

x <- 1
f <- function(a = x) { x <- 2; a }
f()
## [1] 2

Note that a does not have the default 1; it has the default 2. It looks first in the function itself for the default. In a similar way a=a would cause a to be its own default which is circular.

like image 44
G. Grothendieck Avatar answered Oct 08 '22 12:10

G. Grothendieck