Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R: why providing a list to ellipsis (...) when ellipsis is the last argument does not work?

I was writing a function which takes advantage of an ellipsis (aka ...). It lets you specifiy a variable number of additional arguments. I wanted to provide a list with arguments as an additional argument. Below is a reproducible example:

f <- function(..., a =1, b = 2){
  l <- list(...)
  print(l)
}
f(list(a = 2))

[[1]]
[[1]]$a
[1] 2

The goal of providing additional arguments in a list was to avoid names conflict (the function inside f could take an argument named a and I wanted to ensure the possibility of providing it).

While changing implementation I noticed that moving ellipsis to the last place in function declaration returns different result (namely, an empty list):

g <- function(a =1, b = 2, ...){
  l <- list(...)
  print(l)
}
g(list(a = 2))

list()

Being curious, I added printing the default arguments to both functions:

f <- function(..., a =1, b = 2){
  l <- list(...)
  print(l)
  print(c(a = a, b = b))
}
g <- function(a =1, b = 2, ...){
  l <- list(...)
  print(l)
  print(c(a = a, b = b))
}

f(list(a = 2)) # results of calling f
[[1]]
[[1]]$a
[1] 2


a b 
1 2

g(list(a = 2)) # results of calling g
list()
$a.a
[1] 2

$b
[1] 2

So, the first function (f) returned the intended output but the second one (g) ignored(?) the default argument a and somehow modified the list provided thanks to ellipsis.

I would like to understand why both outputs differ from each other. Does it mean that passing a list as an additional argument is possible only when an ellipsis is a first argument in a function call?

like image 853
kaksat Avatar asked Jan 29 '23 10:01

kaksat


1 Answers

The way arguments work in R is that when you don't name your first argument, R just assumes that goes into the first argument for the function. This is true for the second, third and so forth arguments in the argument list EXCEPT for arguments that come after the ... - because R doesn't know how many arguments you intend to fit into the ..., if you want to change the default of whatever comes after it, you have to name it.

So in your case, when you call function f(), the object list(a=2) goes into the .... But in g(), that same object goes into a. The only way you can get something into ... when that is placed at the end of the argument list without including arguements for a and b is to name it something that isn't a or b, e.g. g(c=list(a=1)).

like image 53
iod Avatar answered Jan 31 '23 09:01

iod