While reviewing an R package at work I realized I wasn’t totally sure what advice to give about examples for internal functions in a package.

That is, there’s an R package. The package has some exported functions, and some internal functions that are not exported.

Internal functions are not loaded when the package loads so the normal flow of running examples under roxygen2 tag @examples doesn’t work (assuming you don’t prevent it from running any of various ways).

So I asked about this on Mastodon:

Post by @sckottie@fosstodon.org
View on Mastodon

Ideas from the thread included …

Package devtag

A number of friends (Maëlle and Hugo) suggested using package devtag - which creates documentation for an internal function. Maëlle says they use it in igraph. I poked around with it and could not sort out what it does different from existing roxygen2 tags TBH, so am not pursuing this route.

Internal and asNamespace

What my friend Zhian Kamvar does is to use @keywords internal and then use pkg <- asNamespace("package name") to get a proxy for ::: to avoid cran warnings. I’ve used this pattern in tinkr

Other ideas

Export and internal

Poking around at some of my own packages and those of the Posit folks, it seems like this pattern is pretty common for internal functions: use @export and @keywords internal so the function is found in the package namespace but it’s hidden from topic indexes. This allows for any examples for those functions to run - which means that we can be sure examples aren’t out of sync with the code - assuming the examples are actually run.

Tests instead of examples?

Another possible route could be to instead use tests for internal functions instead of examples to avoid this problem. However, this seems like not a great idea since the sort of best practice I’ve heard about with internal functions is that they are free to change because they’re not user facing, and anyway testing of the exported functions that use them will cover the internal functions too?

Other thoughts

Of course some internal functions are not documented at all and thus this whole issue for those functions is void.

Thinking on the different types of functions suggests a number of different distinct-ish types of functions with respect to visibility:

  • exported (user facing, should have great docs; shows up in pkgdown site)
  • exported internal with docs (using @export and @keywords internal; exists in pkgdown site but not in ref list)
  • internal with docs (using @keywords internal; exists in pkgdown site but not in ref list)
  • plain ol internal (no roxygen2 comments; not in pkgdown site at all)

What to do?

I think the advice I’ll give for now is to use a combination of @export and @keywords internal when the use case is a function that is not meant to be user facing but would benefit from making sure its examples are actually working rather than rotting on the vine.