Hi all,
I believe that 'do.call' shows inconsistent/undocumented behavior when its
'what' argument is of the format "pkg::fun". The documentation (?do.call)
suggests that
what: either a function or a non-empty character string naming the
function to be called.
Thus, I expected that all four of below formats of the value for the
'what' argument would work, here I use 'utils::person' as an example:
Three formats work:
do.call(person, list(given = "Jane", family = "Doe"))
do.call("person", list(given = "Jane", family = "Doe"))
do.call(utils::person, list(given = "Jane", family = "Doe"))
but the format "pkg::fun" doesn't work as I expected:
do.call("utils::person", list(given = "Jane", family = "Doe"))
Error in `utils::person`(given = "Jane", family = "Doe") :
could not find function "utils::person"
This seemingly inconsistent behavior of 'do.call' is also exposed when
working in parallel and the message doesn't make it easy to see that this
error derives actually from 'do.call'.
library(parallel)
cl <- makePSOCKcluster(2)
clusterCall(cl, person, list(given = "Jane", family = "Doe"))
clusterCall(cl, "person", list(given = "Jane", family = "Doe"))
clusterCall(cl, utils::person, list(given = "Jane", family = "Doe"))
clusterCall(cl, "utils::person", list(given = "Jane", family = "Doe"))
Error in checkForRemoteErrors(lapply(cl, recvResult)) :
2 nodes produced errors; first error: could not find function
"utils::person"
This is again not obvious from the documentation (?clusterCall): fun, FUN:
function or character string naming a function.
This behavior of 'clusterCall' is because the function 'makePSOCKcluster'
calls newPSOCKnode() which calls .slaveRSOCK(), which calls slaveLoop().
This is then waiting and on receving an appropriate message will call
'do.call':
value <- tryCatch(do.call(msg$data$fun, msg$data$args, quote = TRUE),
error = handler)
Thus, if 'msg$data$fun' (as received from recvData() which was sent via
sendData(), via postNote() from function sendCall() wrapped in
clusterCall()) is of the type "pkg::fun", then this will fail as above and
work otherwise.
## Temporary work-around: re-define function in local namespace and export
to workers
temp_fun <- function(...) utils::person(...)
clusterExport(cl, "temp_fun")
clusterCall(cl, "temp_fun", list(given = "Jane", family = "Doe"))
## Motivation: I learned about this behavior of 'do.call' when attempting
to write code such as
Rmpi::mpi.bcast.cmd(mypackage2::fun, ...)
in my package1. The function Rmpi::mpi.bcast.cmd() calls eventually
something along the lines of
scmd <- scmd <- substitute(cmd)
arg <- list(...)
scmd.arg <-serialize(list(scmd=scmd, arg=arg), NULL)
if (length(scmd.arg$args) > 0)
do.call(as.character(scmd.arg$$scmd), scmd.arg$args, envir =
.GlobalEnv)
and thus expresses this same inconsistent behavior of do.call. I cannot
avoid calling with pkg::fun because a package should not attach another
package and change the search path of the user.
## My installation
R version 3.4.1 (2017-06-30)
Platform: x86_64-apple-darwin16.6.0 (64-bit)
Running under: macOS Sierra 10.12.5
Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/
A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /opt/local/Library/Frameworks/R.framework/Versions/3.4/
Resources/lib/libRlapack.dylib
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] stats graphics grDevices utils datasets methods base
loaded via a namespace (and not attached):
[1] compiler_3.4.1
I would appreciate any help with identifying whether this is indeed
inconsistent/undocumented behavior of 'do.call' or whether I am simply
missing the point and how to deal with the situation.
Thank you,
Daniel Schlaepfer