get function parameter names/values from within the function body

In many programming languages there is a mechanism to get a list of the formal parameter names and their associated values of the calling function from within the function -- typically as an array or a named list. For instance, if I ran:

tms100 <- function(multiplicand) return(multiplicand * 100)
tms100("Happy Birthday ")

I'd like the error message to say '"Happy Birthday" is not numeric.', rather than "multiplicand is not numeric."
I'd like to be able to consult an object within the called function's scope that gives not just the formal parameter name of the value that causes the error, but the name of the erroneous object in the called function's parent scope. Is there a mechanism to accomplish this within R? Thanks in advance to anyone that can tell me how to do this.
Larry Hunsicker

Are you after something like this using rlang::abort()?

multiplicand <- function(number){
  
  if(!is.numeric(number)){
    rlang::abort(glue::glue("'{number}' is not numeric"))
  } else {
    return(number * 100)
  }
}

# testing ----
multiplicand(20)
[1] 2000

multiplicand("Happy Birthday")
Error during wrapup: 'Happy Birthday' is not numeric
Error: no more error handlers available (recursive errors?); invoking 'abort' restart

Thanks, williaml. Your solution works for the problem that I set, but not for what I was looking for. After noodling around some more, I found the solution in IRTFM's reply/solution in:

Use deparse(subsitiute() as in the code below:

#  Create a (nonsense) data.frame and survfit object:
library(survival)
library(glue)
library(magrittr)
library(dplyr)
data1 <- data.frame(status = sample(0:1, 50, replace = T), sex = sample(0:1, 50, replace = T))
data1 %<>% mutate(time1 = ifelse(status == 1, rnorm(50, 5,2), .2*rnorm(50,5,2)), 
                  time1 = ifelse(sex == 1, time1 + 5, time1))
data1$time1 <- with(data1, ifelse(time1 <=0, 0.1, time1))
data1$time <- with(data1, ifelse(sex == 1, time1 + 2, time1))
fit1 <- survfit(Surv(time1, status) ~ sex, data = data1)

#  create a function to test whether there is a mismatch in length between the model and the parameter levels.
matchlength <- function(sfit, strata) {
  modnm <- deparse(substitute(sfit))
  if (length(unique(summary(sfit)$strata)) == length(strata))
    return(strata)
  else 
    stop(glue("{modnm} has {length(sfit$strata)} strata; length(strata) is {length(strata)}."), call. = F)
}

#  Test the models with a correct length match and one with a length mismatch.
matchlength(fit1, strata = c("IAK", "IA"))
# [1] "IAK" "IA" 
matchlength(fit1, strata = c("IAK", "IA", "IAB"))
# Error: fit1 has 2 strata; length(strata) is 3.

As I understand it, the function call passes the body of the parameter to the function's scope. But a reference to the passed parameter returns the print version of the call not the name of the object in the parent environment. Generally, the print value of a call is the same as the name of the object in the parent scope. But the print() version of lots of functions is the result of the function, not the name of the function in the parent environment. The example here is that if "a" is a survfit object, print(a) gives a formatted output of the function. To get the name of the object in the parent scope, one uses deparse(substitute(a)).

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.