# do.call and alist: a perfect match

Author

Eliot McIntire

Published

August 17, 2020

It has been a while between posts. So, lets dive in with a simple, but technical, one.

### The problem with `do.call`

When developing code in `R`, you often want to call a function with combinations of arguments that you don’t know when you write the function code. One good example is when an outer function uses an argument and then updates it for its own needs, but then passes that new argument to an inner function, e.g.,:

``````sumXY <- function(x, y) {
if (missing(x)) return("x was missing")
if (missing(y)) return("y was missing")
x + y
}

useAndUpdateY <- function(x, ...) {
dots <- list(...)
if (!is.null(dots\$y)) {
message("y was provided; I want to use y and modify x as a result")
y <- dots\$y
y <- x * y # update y
}
# Now, normally, we use '...' formulation in R
sumXY(x = x, ...)
}
(out <- useAndUpdateY(x = 2, y = 3)) # Returns 5 -- Wrong!``````
``## y was provided; I want to use y and modify x as a result``
``##  5``

Basically, this returns the wrong answer because the inner function must live with the original values of the `...`, in this case, `y = 3`

### Solution, part 1 – use `do.call`

We can use `do.call` to construct the arguments as a `list`, giving us immense flexibility.

``````sumXY <- function(x, y) {
if (missing(x)) return("x was missing")
if (missing(y)) return("y was missing")
x + y
}

useAndUpdateY <- function(x, ...) {
dots <- list(...)
if (!is.null(dots\$y)) {
message("y was provided; I want to use y and modify x as a result")
y <- dots\$y
y <- x * y # update y
}
# Now, normally, we use '...' formulation in R
do.call(sumXY, list(x = x, y = y))
}
(out <- useAndUpdateY(x = 2, y = 3)) # returns 8! correct!``````
``## y was provided; I want to use y and modify x as a result``
``##  8``

The main problem with this is that it evaluates `list(x = x, y = y)` before passing it into `sumXY`. For small objects, this can be unnoticeable. But for large objects, including, in our experience, all `sp::SpatialPolygons` objects, this can be unbearable. In interactive `R` sessions (including `Rstudio`), the user will lose access to the command prompt for minutes to hours as `R` attempts to `print` the entire object.

### Solution part 2 – use `alist`

Basically, `alist` is almost identical to `list`, but it doesn’t evaluate the arguments before passing them along to `do.call`. In the help manual for `?alist`, this is stated, but it is under-emphasized:

alist handles its arguments as if they described function arguments. So the values are not evaluated …

``````sumXY <- function(x, y) {
if (missing(x)) return("x was missing")
if (missing(y)) return("y was missing")
x + y
}

useAndUpdateY <- function(x, ...) {
dots <- list(...)
if (!is.null(dots\$y)) {
message("y was provided; I want to use y and modify x as a result")
y <- dots\$y
y <- x * y # update y
}
# Now, normally, we use '...' formulation in R
do.call(sumXY, alist(x = x, y = y)) # update to `alist`
}
(out <- useAndUpdateY(x = 2, y = 3)) # returns 8! still correct!``````
``## y was provided; I want to use y and modify x as a result``
``##  8``

## Conclusion

Always use `alist` when using `do.call`, even for small problems.