30.3 Declaring Dependencies: Depends, Suggests, Imports

List all dependencies in the DESCRIPTION file. Every package that is used by your package’s code must appear in exactly one of the sections Depends, Imports, or Suggests.

Please list packages in alphabetical order within each section. R doesn’t care about the order, but you will later when you’re trying to check whether this package uses a particular dependency.

  • Imports is the correct place to declare most PEcAn dependencies. This ensures that they get installed, but does not automatically import any of their functions – Since PEcAn style prefers to mostly use :: instead of importing, this is what we want.

  • Depends is, despite the name, usually the wrong place to declare PEcAn dependencies. The only difference between Depends and Imports is that when the user attaches your packages to their own R workspace (e.g. using library("PEcAn.yourpkg")), the packages in Depends are attached as well. Notice that a call like PEcAn.yourpkg::yourfun() will not attach your package or its dependencies, so your code still needs to import or ::-qualify all functions from packages listed in Depends. In short, Depends is not a shortcut, is for user convenience not developer convenience, and makes it easy to create subtle bugs that appear to work during interactive test sessions but fail when run from scripts. As the R extensions manual puts it (emphasis added):

    This [Imports and Depends] scheme was developed before all packages had namespaces (R 2.14.0 in October 2011), and good practice changed once that was in place. Field ‘Depends’ should nowadays be used rarely, only for packages which are intended to be put on the search path to make their facilities available to the end user (and not to the package itself)."

  • The Suggests field can be used to declare dependencies on packages that make your package more useful but are not completely essential. Again from the R extensions manual:

    The Suggests field uses the same syntax as Depends and lists packages that are not necessarily needed. This includes packages used only in examples, tests or vignettes (see Writing package vignettes), and packages loaded in the body of functions. E.g., suppose an example from package foo uses a dataset from package bar. Then it is not necessary to have bar use foo unless one wants to execute all the examples/tests/vignettes: it is useful to have bar, but not necessary.

    Some of the PEcAn model interface packages push this definition of “not necessarily needed” by declaring their coupled model package in Suggests rather than Imports. For example, the PEcAn.BIOCRO package cannot do anything useful when the BioCro model is not installed, but it lists BioCro in Suggests because PEcAn as a whole can work without it. This is a compromise to simplify installation of PEcAn for users who only plan to use a few models, so that they can avoid the bother of installing BioCro if they only plan to run, say, SIPNET.

    Since the point of Suggests is that they are allowed to be missing, all code that uses a suggested package must behave reasonably when the package is not found. Depending on the situation, “reasonably” could mean checking whether the package is available and throwing an error as needed (PEcAn.BIOCRO uses its .onLoad function to check at load time whether BioCro is installed and will refuse to load if it is not), or providing an alternative behavior (PEcAn.data.atmosphere::get_NARR_thredds checks at call time for either parallel or doParallel and uses whichever one it finds first), or something else, but your code should never just assume that the suggested package is available.

    You are not allowed to import functions from Suggests into your package’s namespace, so always call them in ::-qualified form. By default R will not install suggested packages when your package is installed, but users can change this using the dependencies argument of install.packages. Note that for testing on Travis CI, PEcAn does install all Suggests (because they are required for full package checks), so any of your code that runs when a suggested package is not available will never be exercised by Travis checks.

    It is often tempting to move a dependency from Imports to Suggests because it is a hassle to install (large, hard to compile, no longer available from CRAN, currently broken on GitHub, etc), in the hopes that this will isolate the rest of PEcAn from the troublesome dependency. This helps for some cases, but fails for two very common ones: It does not reduce install time for CI builds, because all suggested packages need to be present when running full package checks (R CMD check or devtools::check or make check). It also does not prevent breakage when updating PEcAn via make install, because devtools::install_deps does not install suggested packages that are missing but does try to upgrade any that are already installed to the newest available version – even if the installed version took ages to compile and would have worked just fine!