Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Helper to resolve conflicts #4

Closed
wch opened this issue May 25, 2018 · 9 comments

Comments

@wch
Copy link
Member

commented May 25, 2018

This is from a discussion I had with @hadley about resolving conflicts.

The recommended solution is to assign a value in the global env, like this:

library(dplyr)
#> The following objects are masked from ‘package:stats’:
#> 
#>     filter, lag

lag <- stats::lag

This is a little fragile and changes the behavior from normal. For example, a user might clear their workspace by pressing the broom button in RStudio, or by doing rm(list=ls()), and that would reset the conflict resolution without any indication that it's happening.

Another issue is that it introduces a slight change in the way R behaves when you assign a value with the same name as a function.

Normally, if you assign a variable with the same name as a function, you can still call the function as normal:

## In a new R session
lag <- 100
lag(1:3)   # Calls stats::lag
#> [1] 1 2 3
#> attr(,"tsp")
#> [1] 0 2 1

But if you've resolved a conflict by assigning it in the global env, then assigning a value to the same name will undo the resolution. For example:

library(dplyr)
lag <- stats::lag
lag <- 100
lag(1:3)   # Calls dplyr::lag
#> [1] NA  1  2

One possible solution that @hadley suggested is to add a function win:

# Make dplyr win all conflicts
conflicted::win(dplyr)

# Make dplyr win one conflict
conflicted::win(dplyr, filter)
# or 
conflicted::win(dplyr::filter)

The drawbacks here are that it's one more thing to learn, and that the package would need to have an exported function.

@hadley hadley changed the title Possible Helper to resolve conflicts May 29, 2018

@barryrowlingson

This comment has been minimized.

Copy link

commented May 31, 2018

I played with this and you can "resolve" conflicts by smashing the definition in the environment in the search path (position 2 usually). For example, if you want dplyr::filter to win, then win would have to:

rm("filter",pos=2);assign("filter",dplyr::filter,pos=2)

so now that environment acts as a switching yard for conflicted functions.

@hadley

This comment has been minimized.

Copy link
Member

commented May 31, 2018

Currently, that environment is wiped out every time you load a new package, so I wouldn't recommend working in it at the moment.

@lionel-

This comment has been minimized.

Copy link
Member

commented Jun 1, 2018

I think this is starting to look like an imports env that sits between the global env and the package envs. You could import single functions or whole packages at a time but importing a symbol that already exists in that environment would throw a warning (or an error?).

Basically the same pattern as for packages' imports, but for (and shared by) users and sourced scripts.

@hadley

This comment has been minimized.

Copy link
Member

commented Jun 1, 2018

I don’t think this is an imports env, as we’d never support preferring packages as a whole.

@lionel-

This comment has been minimized.

Copy link
Member

commented Jun 1, 2018

Even without this feature isn't it an imports env?

I think allowing importing whole packages would be convenient, users could import stats or Biobase and move on to their script.

It'd be nice to provide a shortcut to this env so you can do:

.imports$lag <- stats::lag

The $<- method would issue warnings appropriately.

@hadley

This comment has been minimized.

Copy link
Member

commented Jun 1, 2018

That is definitely not the intent of the conflicts package.

@mikmart

This comment has been minimized.

Copy link

commented Jun 7, 2018

Rather than (or pehaps along with?) making a given function from a package able to always win a conflict, would it make sense to be able to define the result of a single specific conflict between two packages?

As an example, I use stats::filter precisely never, while I often use dplyr::filter. I would love to be able to use conflicted, but would very much prefer to not to have to write out dplyr::filter every time because of the conflict with stats::filter. However, if I load dplyr and another package that defines filter (e.g. narray currently on CRAN) I would want to get the conflict error.

Essentially, I would like to be able to specify that when dplyr::filter conflicts with with stats::filter, dplyr::filter should win. So something like:

conflicted::win(dplyr::filter, stats::filter)

Perhaps this could be extended to a form of conflicted::win(winner, ...) where ... would be all the specified "losers?"

@hadley

This comment has been minimized.

Copy link
Member

commented Jun 7, 2018

Yeah I very much like that idea - then library(tidyverse) could declare that dplyr::filter beats stats::filter but would still generate conflicts with other filter functions.

This will probably need to wait until I employ a different strategy for computing the conflicts, and after a thorough review of the other means of conflict resolution that we need.

@hadley

This comment has been minimized.

Copy link
Member

commented Jul 24, 2018

Latest syntax iteration:

conflict_prefer("filter", "dplyr")
#> [conflicted] will prefer dplyr::filter() over any other package

conflict_prefer("filter", "dplyr", "base")
#> [conflicted] will prefer dplyr::filter() over base::filter()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants
You can’t perform that action at this time.