3

I may not be using the terminology correctly here so please forgive me...

I have a case of one package 'overwriting' a function with the same name loaded by another package and thus changing the behavior (breaking) of a function.

The specific case:

X <- data.frame ( y = rnorm(100), x1 = rnorm(100), x2 = rnorm(100) )

library(CausalImpact)
a <- CausalImpact::CausalImpact( X, c(1,75), c(76, 100) ) # works

library(bfast) # imports quantmod which loads crappy version of as.zoo.data.frame

b <- CausalImpact::CausalImpact( X, c(1,75), c(76, 100) ) # Error

I know the error comes from two versions of the function as.zoo.data.frame. The problematic version is imported by bfast from the package 'quantmod' (see https://github.com/joshuaulrich/quantmod/issues/168). Unfortunately their hotfix did not prevent this error. Super annoying.

I can hack around this specific problem, but I was wondering if there is a general way to like 'de-register' this function variant from the search path. Neither detach nor unloadNamespace remove the offending function (same behavior after). An explanation and similar problem is discussed here and here, but I wasn't able to find a general solution. For instance I'd rather just remove this function than clone and re-write CausalImpact to deal with this behavior.

user3357177
  • 355
  • 2
  • 9
  • The usual way to deal with this is to load the one with the version you want to use last so it's the first on the search path – alistaire Nov 23 '19 at 06:21
  • If you are using this function only at one specific place instead of loading the library . you can use `::` i.e `CausalImpact::CausalImpact` or `bfast::CausalImpact`. – Ronak Shah Nov 23 '19 at 06:59
  • @alistaire Unfortunately that does not work in this case. This may partly be due to the fact that the error is generated by a dependency of one package (quantmod) – user3357177 Nov 25 '19 at 02:44
  • @RonakShah Sorry, clarified that CausalImpact is not a function in bfast and is thus not overwritten – user3357177 Nov 25 '19 at 02:45

2 Answers2

9

From R 3.6.0 onwards, there is a new option called "conflicts.policy" to handle this within an established framework. For small issues like this, you can use the new arguments to library(). If you aren't yet to 3.6, the easiest solution might be to explicitly namespace CausalImpact when you need it, i.e. CausalImpact::CausalImpact. That's a mouthful, so you could do causal_impact <- CausalImpact::CausalImpact and use that alias.

# only attach select
library(dplyr, include.only = "select")
# exclude slice/arrange from being attached.
library(dplyr, exclude = c("slice", "arrange")) 

library(bfast, exclude = "CausalImpact") should solve your problem.

Attach means that they are available for use without explicit prefixing with their package. In either of these cases, something like dplyr::slice would work just fine.

For more information, you can see ?library. Also, the R-Core member Luke Tierney wrote a blog explaining how the conflicts.policy works. You can find that here

smingerson
  • 1,368
  • 9
  • 12
  • thanks @smingerson. Unfortunately exclude isn't seeming to work in this case. If I try library(bfast, exclude = 'as.zoo.data.frame'), nothing changes because the offending function is actually from quantmod, a package that bfast loads. When I try to first load quantmod without this change: library(quantmod, exclude = 'as.zoo.data.frame') the function is still overwritten. I know this because R 6.0.1 gives me the message "Registered S3 method overwritten by 'quantmod': method - as.zoo.data.frame; from - zoo. If I try to exclude another random function from quantmod, the exclude call works. – user3357177 Nov 25 '19 at 03:20
  • 1
    You could try defining the as.zoo.data.frame method within your script as defined in the zoo package. Kinda crazy someone would overwrite that... I don't think methods are typically exported using the same mechanism, so that could be why it failed. – smingerson Nov 25 '19 at 03:34
  • Yeah, the quantmod version actually preceded the zoo version, strangely enough https://github.com/joshuaulrich/quantmod/issues/168 – user3357177 Nov 25 '19 at 03:45
0

Here's an answer that works, but is less preferable than de-registering a S3 method because it involves replacing the registered version in the S3 Methods table with the desired method:

library(CausalImpact)
library(bfast) 
assignInNamespace("as.zoo.data.frame", zoo:::as.zoo.data.frame, ns = asNamespace("zoo"))

based partially on @smingerson's suggestion in the comments

user3357177
  • 355
  • 2
  • 9