8

.Call seems rather poorly documented; ?.Call gives an explanation of the PACKAGE argument:

PACKAGE: if supplied, confine the search for a character string .NAME to the DLL given by this argument (plus the conventional extension, ‘.so’, ‘.dll’, ...).

This argument follows ... and so its name cannot be abbreviated.

This is intended to add safety for packages, which can ensure by using this argument that no other package can override their external symbols, and also speeds up the search (see ‘Note’).

And in the Note:

If one of these functions is to be used frequently, do specify PACKAGE (to confine the search to a single DLL) or pass .NAME as one of the native symbol objects. Searching for symbols can take a long time, especially when many namespaces are loaded.

You may see PACKAGE = "base" for symbols linked into R. Do not use this in your own code: such symbols are not part of the API and may be changed without warning.

PACKAGE = "" used to be accepted (but was undocumented): it is now an error.

But there are no usage examples.

It's unclear how the PACKAGE argument works. For example, in answering this question, I thought the following should have worked, but it doesn't:

.Call(C_BinCount, x, breaks, TRUE, TRUE, PACKAGE = "graphics")

Instead this works:

.Call(graphics:::C_BinCount, x, breaks, TRUE, TRUE)

Is this simply because C_BinCount is unexported? I.e., if the internal code of hist.default had added PACKAGE = "graphics", this would have worked?

This seems simple but is really rare to find usage of this argument; none of the sources I found give more than passing mention (1, 2, 3, 4, 5)... Examples of this actually working would be appreciated (even if it's just citing code found in an existing package)

(for self-containment purposes, if you don't want to copy-paste code from the other question, here are x and breaks):

x = runif(100000000, 2.5, 2.6)
nB <- 99
delt <- 3/nB
fuzz <- 1e-7 * c(-delt, rep.int(delt, nB))
breaks <- seq(0, 3, by = delt) + fuzz
Community
  • 1
  • 1
MichaelChirico
  • 33,841
  • 14
  • 113
  • 198
  • nice question, I just googled it, I found something which can give you some hints in case no one have experience http://www.biostat.jhsph.edu/~bcaffo/statcomp/files/dotCall.pdf –  Jul 18 '16 at 14:55
  • 1
    @Learner indeed that's link 3 from my question – MichaelChirico Jul 18 '16 at 15:00
  • 1
    See, also, [this reference](https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Registering-native-routines) – alexis_laz Jul 18 '16 at 22:10
  • 6
    using .Call on undocumented things from other packages is a really really bad idea and is a perfect example of an undocumented thing that should remain undocumented. Meaning it shouldn't be documented on the SO documentation site. Or anywhere else. – Spacedman Jul 21 '16 at 13:53
  • @Spacedman I categorically disagree with that sentiment. – MichaelChirico Jul 21 '16 at 13:54
  • 2
    @MichaelChirico Sure, but that still doesn't take away from the basic fact that you are ... wrong on this one. – Dirk Eddelbuettel Jul 21 '16 at 14:09

1 Answers1

10

C_BinCount is an object of class "NativeSymbolInfo", rather than a character string naming a C-level function, hence PACKAGE (which "confine(s) the search for a character string .NAME") is not relevant. C_BinCount is made a symbol by its mention in useDynLib() in the graphics package NAMESPACE.

As an R symbol, C_BinCount's resolution is subject to the same rules as other symbols -- it's not exported from the NAMESPACE, so only accessible via graphics:::C_BinCount. And also, for that reason, off-limits for robust code development. Since the C entry point is imported as a symbol, it is not available as a character string, so .Call("C_BinCount", ...) will not work.

Using a NativeSymbolInfo object tells R where the C code is located, so there is no need to do so again via PACKAGE; the choice to use the symbol rather than character string is made by the package developer, and I think would generally be considered good practice. Many packages developed before the invention of NativeSymbolInfo use the PACKAGE argument, if I grep the Bioconductor source tree there are 4379 lines with .Call.*PACKAGE, e.g., here.

Additional information, including examples, is in Writing R Extensions section 1.5.4.

Martin Morgan
  • 45,935
  • 7
  • 84
  • 112
  • Talk about abstruse documentation... I tried `.Call("C_BinCount", x, breaks, TRUE, TRUE, PACKAGE = "graphics")` and got a different error (`"C_BinCount"` not available for `.Call()` for package `"graphics"`)... is this because it's not exported? Is there no way to use the `PACKAGE` argument here to execute the call? – MichaelChirico Jul 18 '16 at 18:18
  • Also, do you know of any _actual_ R code that uses the `PACKAGE` argument? It would be useful to find an example of this "in the wild" – MichaelChirico Jul 18 '16 at 18:18
  • I've updated my answer -- the package author chose not to expose the symbol via a character string, so no amount of typing will make "C_BinCount" work. There are many examples in the wild; I linked to one. – Martin Morgan Jul 18 '16 at 18:36
  • Thanks! I've learned a lot (or at least learned that I have much more to learn). So it seems this argument is kind of a vestige from an age when the `NativeSymbolInfo` approach was unavailable... One last follow-up, where exactly in the package code is `C_BinCount` declared as `NativeSymbolInfo`? – MichaelChirico Jul 18 '16 at 18:39
  • 1
    @MichaelChirico it's made a symbol in the NAMESPACE file useDynLib(); I've updated my answer some more. – Martin Morgan Jul 18 '16 at 19:51
  • 2
    @MichaelChirico RE: actual examples, if you create a package using Rcpp (attributes), the wrapper function(s) generated will use `.Call` with the `PACKAGE` argument. Here is a [minimal example](https://gist.github.com/nathan-russell/7eec0187b598622d390c28296d5c1907#file-rcpp-dot-call-r-L37-L43). – nrussell Jul 18 '16 at 20:28