Reputation: 608
This thread discusses two basic approaches to using functions inside other functions in R: What are the benefits of defining and calling a function inside another function in R?
The top answer says the second approach, naming externally and just calling via name in the outer function, is faster: " f2
needs to be redefined every time you call f1
, which adds some overhead (not very much overhead, but definitely there)". My question is, is this overhead caused by the assignment itself or by passing through the function itself?
For example, consider this third option besides the two in that thread:
#Approach 1
fun1a <- function(x) {
fun1b <- function(y){return(y^2)}
return(fun1b(x))
}
#Approach 2
fun2a <- function(y){return(y^2)}
fun2b <- function(x){return(fun2a(x))}
#Approach 3
fun3 <- function(x) {
return(function(x){return(x^2)})
}
It was confirmed that Approach 2 is faster than Approach 1 because Approach 1 needs to redefine fun1b
in the function repeatedly. But if you use Approach 3 --basically, Approach 1, but not assigning fun1b
to a named function everytime you run it -- is that always faster?
If so, why would anyone not just use Approach 3 for everything? i.e. what disadvantages does it have compared to Approach 2 (or 1)
Upvotes: 3
Views: 2165
Reputation: 269854
Some of these (but not all) are already mentioned in the link in the question but here is a longer list.
Visibility Functions defined within functions are not visible outside that function increasing the modularity of the software if that function is not also used elsewhere. It provides a sort of poor man's namespace. For example, an alternative to using an anonymous function in a lapply
appearing within a function would be to define it as a named function within the outer function to keep it from being visible outside the outer function. The name might form a sort of documentation for the inner function.
Scope Functions defined within functions can access variables defined in the outer function without passing them as arguments.
Cache Functions defined within functions and passed back out can use the outer function to cache results so that they are remembered the next time the passed out function is run. Here makeIncr
is a factory function which constructs a new counter function each time it is run. The counter functions return the next number in sequence each time they are run.
makeIncr <- function(init) function() { init <<- init + 1; init }
counter1 <- makeIncr(0)
counter1()
## [1] 1
counter1()
## [1] 2
counter2 <- makeIncr(0)
counter2()
## [1] 1
Object Orientation Functions defined within functions can be used to emulate a limited form of object orientation. See an example by running: demo(scoping)
Debugging can be a bit more awkward with functions within functions. For example, debug(makeIncr)
using makeIncr
above does not debug the counters which would have to be debugged separately.
I am not sure that the performance issue discussed is really material since the functions would be byte compiled the first time the outer function is run. In most cases you would want to make a decision based on other factors.
Upvotes: 3