Home > Software engineering >  In R, how to pass arguments from the parent to the child function?
In R, how to pass arguments from the parent to the child function?

Time:01-20

I have two functions nested in another function and I would like that the arguments declared in parent were passed to the child (only when the argument is relevant to the function).

# child function 1
child_f1 <- function(x1 = 1, x2 = 3) {
  res <- x1^2   4 * x2
}

# child function 2
child_f2 <- function(z = 2) {
  res <- z * 1.345
}

# parent function
parent_f <- function(y = 4, ...) {
  res <- (child_f1(...) ^ y)   child_f2(...)
  # print(res)
  return(res)
}

Test below:

parent_f(y = 2, x1 = 2, x2 = 0, z = 3)
# Error in child_f1(...) (from #2) : unused argument (z = 3)

# Expected result:
(((2)^2   4*(0)) ^ (2))   (3) * 1.345
[1] 20.04

How do I tell child_f1 that has to use only x1 and x2 (if available, otherwise use default value) and child_f2 that has to use only z(if available, otherwise use default value)?

I would like to stick with the usage of ... rather than re-write a parent_f() with all the possible parameters declared.

CodePudding user response:

Add ... to each child to slurp up the unused arguments. parent_f is unchanged.

child_f1 <- function(x1 = 1, x2 = 3, ...) {
  res <- x1^2   4 * x2
}

child_f2 <- function(z = 2, ...) {
  res <- z * 1.345
}

parent_f(y = 2, x1 = 2, x2 = 0, z = 3)
## [1] 20.035

If you can't modify the children or the parent then use this:

child_f1_orig <- child_f1
child_f1 <- function(x1 = 1, x2 = 3, ...) child_f1_orig(x1 = x1, x2 = x2)

child_f2_orig <- child_f2
child_f2 <- function(z = 2, ...) child_f2_orig(z = z)

parent_f(y = 2, x1 = 2, x2 = 0, z = 3)
## [1] 20.035

CodePudding user response:

We can use formals to reduce the arguments to those supported by the child function. This relies on all arguments being named, which is supported here. After that, we use do.call to programmatically call a function with a list of arguments.

# parent function
parent_f <- function(y = 4, ...) {
  dots <- list(...)
  dots1 <- dots[intersect(names(dots), names(formals(child_f1)))]
  dots2 <- dots[intersect(names(dots), names(formals(child_f2)))]
  res <- (do.call(child_f1, dots1) ^ y)   do.call(child_f2, dots2)
  # print(res)
  return(res)
}

parent_f(y = 2, x1 = 2, x2 = 0, z = 3)
# [1] 20.035

CodePudding user response:

You can make use of formal and design a proper function for your usecase

use_fun_with_args <- function(fun, ...) {
  dots <- list(...)
  do.call(fun, args = dots[intersect(names(formals(fun)), 
                                     names(dots))])
}

# parent function
parent_f <- function(y = 4, ...) {
  res <- (use_fun_with_args(fun = child_f1, ...) ^ y)   use_fun_with_args(fun = child_f2, ...)
  # print(res)
  return(res)
}
parent_f(y = 2, x1 = 2, x2 = 0, z = 3)
#> [1] 20.035
  • Related