Skip to content
An alternative conflict resolution strategy for R
Branch: master
Clone or download
Latest commit 1d41a7b Jun 22, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
R Update rlang API (#41) Jun 14, 2019
man
revdep Update revdeps Jun 21, 2019
tests Dynamically bind shims Mar 29, 2019
.Rbuildignore Run revdeps and update NEWS Mar 29, 2019
.gitignore Build package website Aug 23, 2018
.travis.yml Install pkgdown with travis Mar 29, 2019
CODE_OF_CONDUCT.md Add code of conduct May 20, 2018
DESCRIPTION Increment version number Jun 22, 2019
NAMESPACE Rename conflicts_find to conflict_scout Aug 23, 2018
NEWS.md Increment version number Jun 22, 2019
README.Rmd Rename conflicts_find to conflict_scout Aug 23, 2018
README.md
_pkgdown.yml Add url Sep 16, 2018
codecov.yml
conflicted.Rproj Switch name to conflicted May 20, 2018
cran-comments.md Run revdeps and update NEWS Mar 29, 2019

README.md

conflicted

Travis build status Coverage status CRAN status

The goal of conflicted is to provide an alternative conflict resolution strategy. R’s default conflict resolution system gives precedence to the most recently loaded package. This can make it hard to detect conflicts, particularly when introduced by an update to an existing package. conflicted takes a different approach, making every conflict an error and forcing you to choose which function to use.

Thanks to @krlmlr for this neat idea! This code was previously part of the experimental strict package, but I decided improved conflict resolution is useful by itself and worth its own package.

Installation

# install.packages("devtools")
devtools::install_github("r-lib/conflicted")

Usage

To use conflicted, all you need to do is load it:

library(conflicted)
library(dplyr)

filter(mtcars, cyl == 8)
#> Error: [conflicted] `filter` found in 2 packages.
#> Either pick the one you want with `::` 
#> * dplyr::filter
#> * stats::filter
#> Or declare a preference with `conflicted_prefer()`
#> * conflict_prefer("filter", "dplyr")
#> * conflict_prefer("filter", "stats")

As suggested, you can either namespace individual calls:

dplyr::filter(mtcars, am & cyl == 8)
#>    mpg cyl disp  hp drat   wt qsec vs am gear carb
#> 1 15.8   8  351 264 4.22 3.17 14.5  0  1    5    4
#> 2 15.0   8  301 335 3.54 3.57 14.6  0  1    5    8

Or declare a session-wide preference:

conflict_prefer("filter", "dplyr")
#> [conflicted] Will prefer dplyr::filter over any other package
filter(mtcars, am & cyl == 8)
#>    mpg cyl disp  hp drat   wt qsec vs am gear carb
#> 1 15.8   8  351 264 4.22 3.17 14.5  0  1    5    4
#> 2 15.0   8  301 335 3.54 3.57 14.6  0  1    5    8

I recommend declaring preferences directly underneath the corresponding library call:

library(dplyr)
conflict_prefer("filter", "dplyr")

You can ask conflicted to report any conflicts in the current session:

conflict_scout()
#> 6 conflicts:
#> * `filter`   : [dplyr]
#> * `intersect`: [dplyr]
#> * `lag`      : dplyr, stats
#> * `setdiff`  : [dplyr]
#> * `setequal` : [dplyr]
#> * `union`    : [dplyr]

Functions surrounded by [] have been chosen using one of the built-in rules. Here filter() has been selected because of the preference declared above; the set operations have been selected because they follow the superset principle and extend the API of the base equivalents.

How it works

Loading conflicted creates a new “conflicted” environment that is attached just after the global environment. This environment contains an active binding for any object that is exported by multiple packages; the active binding will throw an error message describing how to disambiguate the name. The conflicted environment also contains bindings for library() and require() that suppress conflict reporting and update the conflicted environment with any new conflicts.

Alternative approaches

It is worth comparing conflicted to modules and import. Both packages provide strict alternatives to library(), giving much finer control over what functions are added to the search path.

# modules expects you to namespace all package functions
dplyr <- modules::import_package('dplyr')
dplyr$filter(mtcars, cyl == 8)

# import expects you to explicit load functions
import::from(dplyr, select, arrange, dplyr_filter = filter)
dplyr_filter(mtcars, cyl == 8)

These require more upfront work than conflicted, in return for greater precision and control.

Code of conduct

Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.

You can’t perform that action at this time.