rnse

Find missing arguments of a calling function


I am trying to write a function that can return which arguments from the calling function are missing.

find_missing_args <- function(...) {
  args <- rlang::enquos(...)
  lapply(args, rlang::is_missing)
}

func <- function(x, y, z) {
  find_missing_args(x, y, z)
}

However, the functionality is not as expected:

func(x = 1, y = 2)

Returns

[[1]]
[1] FALSE

[[2]]
[1] FALSE

[[3]]
[1] FALSE

It should return:

[[1]]
[1] FALSE

[[2]]
[1] FALSE

[[3]]
[1] TRUE

Because z was not supplied in the calling function. I would also like to be able to pass which arguments I care about to find_missing_args, so for example:

find_missing_args <- function(...) {
  args <- rlang::enquos(...)
  lapply(args, rlang::is_missing)
}

func <- function(x, y, z, a, b, c) {
  find_missing_args(x, y, z)
}

func(x = 1, y = 2, a = 3, b = 4) will return:

[[1]]
[1] FALSE

[[2]]
[1] FALSE

[[3]]
[1] TRUE

but ignore a, b, c.

UPDATE WITH ANSWER:

find_missing_args <- function(args) {
  supplied <- rlang::call_args_names(rlang::caller_call(n = 1))
  setdiff(args, supplied)
}

func <- function(x, y, z, a, b, d) {  
  find_missing_args(c("x","y","z"))
}

func(x = 1, y = 2)

[1] "z"

Interestingly,

find_missing_args <- function(args) {
  supplied <- rlang::call_args_names(rlang::caller_call(n = 1))
  setdiff(args, supplied)
}

func <- function(x, y, z, a, b, c) {  
  find_missing_args(c("x","y","z"))
}

func(x = 1, y = 2)

Error in c("x", "y", "z") : argument "c" is missing, with no default

I have not figured out why it interprets c() to be the argument c and not the function c().


Solution

  • I don't delve into these sorts of mechanics often, so I'm not sure how robust or "idiomatic" this is, but I think this gets at what you want?

    find_missing_args <- function(...) {
      a1 <- rlang::call_args_names(rlang::caller_call(n = 1))
      a2 <- rlang::fn_fmls_names(rlang::caller_fn(n = 1))
      setdiff(a2,a1)
    }
    
    func <- function(x, y, z) {
      find_missing_args()
    }
    
    func(x = 1,y = 2)