Sébastien Wouters
Sébastien Wouters

Reputation: 141

Disable partial name idenfication of function arguments

I am trying to make a function in R that outputs a data frame in a standard way, but that also allows the user to have the personalized columns that he deams necessary (the goal is to make a data format for paleomagnetic data, for which there are common informations that everybody use, and some more unusual that the user might like to keep in the format).

However, I realized that if the user wants the header of his data to be a prefix of one of the defined arguments of the data formating function (e.g. via the 'sheep' argument, that is a prefix of the 'sheepc' argument, see example below), the function interprets it as the defined argument (through partial name identification, see http://adv-r.had.co.nz/Functions.html#lexical-scoping for more details).

Is there a way to prevent this, or to at least give a warning to the user saying that he cannot use this name ?

PS I realize this question is similar to Disabling partial variable names in subsetting data frames, but I would like to avoid toying with the options of the future users of my function.

fun <- function(sheeta = 1, sheetb = 2, sheepc = 3, ...)
{
  
  # I use the sheeta, sheetb and sheepc arguments for computations 
  # (more complex than shown below, but here thet are just there to give an example)
  
  a <- sum(sheeta, sheetb)
  
  df1 <- data.frame(standard = rep(a, sheepc))
  
  df2 <- as.data.frame(list(...))
  
  if(nrow(df1) == nrow(df2)){
    
    res <- cbind(df1, df2)
    
    return(res)
    
  } else {
    
    stop("Extra elements should be of length ", sheep)
    
  }
  
}

fun(ball = rep(1,3))
#>   standard ball
#> 1        3    1
#> 2        3    1
#> 3        3    1

fun(sheep = rep(1,3))
#> Error in rep(a, sheepc): argument 'times' incorrect

fun(sheet = rep(1,3))
#> Error in fun(sheet = rep(1, 3)) : 
#>  argument 1 matches multiple formal arguments

Upvotes: 2

Views: 144

Answers (1)

Roland
Roland

Reputation: 132706

From the language definition:

If the formal arguments contain ‘...’ then partial matching is only applied to arguments that precede it.

fun <- function(..., sheeta = 1, sheetb = 2, sheepc = 3)
{<your function body>}

fun(sheep = rep(1,3))
#  standard sheep
#1        3     1
#2        3     1
#3        3     1

Of course, your function should have assertion checks for the non-... parameters (see help("stopifnot")). You could also consider adding a . or _ to their tags to make name collisions less likely.

Edit:

"would it be possible to achieve the same effect without having the ... at the beginning ?"

Yes, here is a quick example with one parameter:

fun <- function(sheepc = 3, ...)
{ 
  stopifnot("partial matching detected" = identical(sys.call(), match.call()))
  list(...)
}

fun(sheep = rep(1,3))
# Error in fun(sheep = rep(1, 3)) : partial matching detected 

fun(ball = rep(1,3))
#$ball
#[1] 1 1 1

Upvotes: 4

Related Questions