Reputation: 41
I have been looking for a way to do object destructuring. This in an effort to write cleaner code when developing packages.
I often have a complex system of functions that call others etc and I want to make those arguments available at the higher level functions to the user.
When developing packages for R
I end up often writing functions that call other functions and end up having to either use the ...
operator (which can only be used once. Or to manually re-assign the object like so:
someFunction1 <- function(arg1, arg2) { print(stringr::str_interp('Do something with ${arg1}, and with ${arg2}')) }
someFunction2 <- function(arg3, arg4) { print(stringr::str_interp('Do something with ${arg1}, and with ${arg2}')) }
# solution with R's ...
someHigherFunction <- function(arg5, arg6, ...) {
# do something with arg5 and 6
someFunction1(...)
}
# otherwise I start having to do this; and the more nested the functions get the harder it is to manage
someHigherFunction <- function(arg5, arg6, arg1, arg2, arg3, arg4) {
# do something with arg5 and 6
someFunction1(arg1 = arg1, arg2 = arg2)
someFunction1(arg3 = arg3, arg4 = arg4)
}
# there is a solution using do.call but it is rather annoying
someHigherFunction <- function(arg5, arg6, arg1_2 = list(arg1 = "something", arg2 = "something else")) {
# do something with arg5 and 6
# not ideal but it works
do.call(someFunction1, arg1_2)
}
In JavaScript
we can use object destructuring (easy for positional arguments), python has this too with it's own **
double star operator:
function foo(a, b) {
console.log(a - b);
}
let args = [10, 7];
foo(...args);
There are other uses for this as well:
let a, b, rest;
[a, b] = [10, 20];
console.log(a);
// expected output: 10
console.log(b);
// expected output: 20
[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(rest);
// expected output: Array [30,40,50]
Does anyone have any suggestions on how to accomplish this in R? Did I miss something?
Upvotes: 1
Views: 298
Reputation: 167
Expanding on above, is this pattern useful/generalizable?
someHigherFunction4 <- function(arg5, arg6, ...) {
# collect arguments passed in dots
args <- match.call(expand.dots = FALSE)$...
# if arguments named, subset dots to avoid unused variable error in do.call
if(!is.null(names(args))) {
validArgs <- formalArgs(someFunction1)
do.call(someFunction1, args[validArgs])
} else {
# if not, pass arguments by position
do.call(someFunction1, as.list(args))
}
}
someHigherFunction4("foo", TRUE, "this", "that")
# result: "Do something with this, and with that"
someHigherFunction4("foo", TRUE, arg1 = "this", arg2 = "that", arg3 = "bar")
# result: "Do something with this, and with that"
Upvotes: 1