Putting dependencies used by a single function as `Suggests`

Some package authors try to reduce the number of hard dependencies (Depends & Imports) of their package by putting packages used by a single function as Suggests and conditionally prompt to install the package if missing when the function is called:

my_fct <- function(args) {

  if (!requireNamespace("dependency", quietly = TRUE)) {
    stop("You need to install the 'dependency' package to use this function")
  }

}

Is this considered good practice?

1 Like

I personally don’t think it’s good practice in 2022.

As a novice user, I used to find this confusing because it’s asking the user to manually manage dependencies when they are usually managed automatically by R. I didn’t understand why automatic installation didn’t happen for these particular dependencies and got confused about R package installation and dependency management.

One common argument in favour of low-dependency packages is that “dependencies are an invitation for other people to break your package” (1). But this argument does not apply here since the dependency is still present. Any breaking update to this dependency will still break the function.

Another argument is that dependencies can be long to install, especially when you have to compile them. However, I don’t think this argument is still valid now that we have projects like RStudio package manager or [CRAN - Package bspm] which provide pre-compiled binaries even for common Linux distributions.

Overall, I don’t think this approach of artificially demoting hard-dependencies as Suggests should still be used in 2022. This only case when this might make sense in my opinion is when you reach the hard limit of 20 Depends + Imports enforced by CRAN. But even then, I think there are better options to reduce the number of hard dependencies.

2 Likes

I broadly agree and would add that before I debate if I want to add a dependency I always build a package lockfile with {pak} which makes it easy to see if I maybe already have the package in question as an indirect dependency, which makes it free to add as a direct dependency.

I do agree broadly with your ideas @Bisaloo but I think this has to be, as always in programming, decided on a case by case basis. For example I use openssl in a single function, with a very specific use case, for cryptographic randomness. I ward this function and add openssl to Suggests because it requires a system dependency. Outside of its intended use environment (Github Actions) I use an unsafe fallback and document this. (see here)

3 Likes