Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically switch package in `::` call in R

Tags:

package

r

Given a call to a function bar::foo(), I would like to be able to programmatically switch the package bar so that the same syntax calls hello::foo().

An example:

  • Let's say I have three packages, parentPkg, childPkg1 and childPkg2.
  • In parentPkg I have a call to function childPkg1::foo()
  • foo() is also a function in childPkg2
  • I would like to be able, in parentPkg to use the :: operator to call foo() but to programatically switch the package name. Something like:

    dummy_pkg_name = ifelse(scenario=="child1", "childPkg1", "childPkg2")
    dummy_pkg_name::foo()
    

Is it possible? How do I achieve it?

Some context

parentPkg is a function that interacts with a web application, takes some request and data and returns results from different statistical models depending on the scenarios.
Each scenario is quite complex and not everything can be generalised in parentPkg. For this reason, childPkg1 and childPkg2 (actually there are also 3 and 4) are sort of sub-packages that deals with the data cleaning and various alternatives for each scenario but return the same class of value.
The idea is that parentPkg would switch the package to the pertinent child depending on the scenario and call all of the necessary functions without having to write the same sequence for each child but just with a slightly different :: call.

like image 418
Duccio A Avatar asked Dec 30 '18 14:12

Duccio A


People also ask

How to use switch () function in R?

R language supports a built-in function called switch () which is used to apply the switch case logic in the R program. The switch statement in R accepts the expression and the cases as function parameters for the evaluation of the cases for developing the program logic.

What is switch case in R?

Switch case in R. Switch case statements are a substitute for long if statements that compare a variable to several integral values. Switch case in R is a multiway branch statement. It allows a variable to be tested for equality against a list of values.

What are the tidyverse packages in R language?

What Are the Tidyverse Packages in R Language? Switch case statements are a substitute for long if statements that compare a variable to several integral values. Switch case in R is a multiway branch statement. It allows a variable to be tested for equality against a list of values.

What is switch in C++ with example?

switch (expression, list) Here, the expression is evaluated and based on this value, the corresponding item in the list is returned. If the value evaluated from the expression matches with more than one item of the list, switch () function returns the first matched item. Example: switch () function


3 Answers

Since :: can be seen as a function, it looks like

`::`(dummy_pkg_name, foo)()

is what you want. Alternatively,

getFromNamespace("foo", ns = dummy_pkg_name)()

For instance,

`::`(stats, t.test)
# function (x, ...) 
# UseMethod("t.test")
# <bytecode: 0x102fd4b00>
# <environment: namespace:stats>

getFromNamespace("t.test", ns = "stats")
# function (x, ...) 
# UseMethod("t.test")
# <bytecode: 0x102fd4b00>
# <environment: namespace:stats>
like image 126
Julius Vainora Avatar answered Nov 08 '22 14:11

Julius Vainora


To adhere to KISS, simply re-assign to new named functions in global environment. Be sure to leave out () since you are not requesting to run the function.

parent_foo <- parentPkg::foo
child1_foo <- childPkg1::foo
child2_foo <- childPkg2::foo
child3_foo <- childPkg3::foo

Then, conditionally apply them as needed:

if (scenario=="child1") {
  obj <- child1_foo(...)
} 
else if (scenario=="child2") {
  obj <- child2_foo(...)
} 
...
like image 25
Parfait Avatar answered Nov 08 '22 16:11

Parfait


You could also create a call() that could then be evaluated.

call("::", quote(bar), quote(foo()))
# bar::foo()

Put into use:

c <- call("::", quote(stats), quote(t.test))
eval(c)
# function (x, ...) 
# UseMethod("t.test")
# <bytecode: 0x4340988>
# <environment: namespace:stats>

Wrapped up in a function using setdiff as our default function:

f <- function(pkg, fn = setdiff) {
    pkg <- substitute(pkg)
    fn <- substitute(fn)
    eval(call("::", pkg, fn))
}

f(base)
# function (x, y) 
# {
#     x <- as.vector(x)
#     y <- as.vector(y)
#     unique(if (length(x) || length(y)) 
#         x[match(x, y, 0L) == 0L]
#     else x)
# }
# <bytecode: 0x30f1ea8>
# <environment: namespace:base>

f(dplyr)
# function (x, y, ...) 
# UseMethod("setdiff")
# <environment: namespace:dplyr>
like image 33
Rich Scriven Avatar answered Nov 08 '22 16:11

Rich Scriven