1

I wonder what the best way to handle masking conflicts the right way if the conflicting packages are not my own packages. Consider the following example. I work a lot with time series and typically function names like quarter, year etc. are used quite often. So if I load tis and data.table the functionality of R clearly depends on the sequence the packages are loaded.

library(tis)
library(data.table)
# this masks: between, month, quarter, year
library(TSfame) # loads TSdbi
con <- TSconnect("somefame.db")
# the following fails when data.table was loaded after tis
ts1 <- TSget("somekeyInYourDB",con)

and TSget from the TSdbi package does not work anymore. Do I need to fork the package and implement some :: syntax? The example might be specific, but the question is pretty general. What would more experienced users do?

EDIT: Probably I need to state this more clearly. The problem is that I don't have a chance to call the function explicitly because TSget is calling the function that should be called explicitly and assumes that there's only tis.

EDIT2, adding the call stack as requested by Richie Cotton:

 Tracing year(actualStart) on entry 
 [[1]]
 TSget("kofbauindikator_total", con)

 [[2]]
  TSget("kofbauindikator_total", con)

 [[3]]
 .local(serIDs, con, ...)

 [[4]]
  getfame(serIDs[i], dbname[i], save = FALSE, envir = parent.frame(), 
  start = NULL, end = NULL, getDoc = FALSE)

  [[5]]
  year(actualStart)

   [[6]]
  .doTrace((function () 
  print(sys.calls()))(), "on entry")

 [[7]]
 eval.parent(exprObj)

 [[8]]
 eval(expr, p)

 [[9]]
 eval(expr, envir, enclos)

 [[10]]
 (function () 
  print(sys.calls()))()

 Error in as.POSIXlt.default(x) : 
    do not know how to convert 'x' to class “POSIXlt”
Matt Bannert
  • 27,631
  • 38
  • 141
  • 207
  • 1
    I'm missing something here, since `TSget` doesn't call `quarter`, of any of the conflicting functions. Is the problem (1) that a function in `TSfame` calls a function in `tis`, but you want it to call a function in `data.table`, or (2) that the function in `TSfame` sometimes calls a function in `tis` and sometimes calls a function in `data.table`, depending upon the `search()` path? – Richie Cotton Oct 20 '14 at 10:20
  • The problem is that `TSget` DOES call `quarter` or any of the conflicting functions. If I don't load data.table at all everything works. If I call data.table one of those 4 masked functions is called instead of the tis function. So 2) is actually exactly my problem. – Matt Bannert Oct 20 '14 at 10:29
  • 1
    I have a hunch that the problem may be that `TSfame` should Import `TSdbi` rather than Depending upon it (see http://stackoverflow.com/q/8637993/134830) but please could you provide an example that reproduces the problem to make it easier to confirm this. – Richie Cotton Oct 20 '14 at 10:34
  • Hard to do something really reproducible because nobody got FAME. However I improved the example a little bit so you can at least reproduce it if you got FAME. I believe this specific problem is within the package `tis`, not TSfame, but apart from these specific package how would you approach such a problem? – Matt Bannert Oct 20 '14 at 11:26
  • Please can you trace the `data.table::quarter` function like this: `trace(data.table::quarter, function() print(sys.calls()))` and rerun your example, then add the call stack to your question so we can see where the problem is occurring. Thanks. – Richie Cotton Oct 20 '14 at 12:04
  • Thanks for the pointer! Ok, so data.table::year is the villain, not quarter, but it does not change to actual question. – Matt Bannert Oct 20 '14 at 12:11
  • 1
    One easy thing to do is to determine which package you use the least and load that only for the duration of its use and then immediately detach it again before using the conflicting package: `library(PkgA); ...; library(PkgB); ...; detach("package::PkgB"); ...` where PkgB is only used in the middle `...` and PkgA is only used in the outer ones. – G. Grothendieck Oct 20 '14 at 16:22

1 Answers1

1

The call stack shows that the ambiguously named function, year, is called by getfame. getAnywhere("getfame") reveals that this is found in the fame package.

packageDescription("fame") reveals that fame depends upon tis rather than importing it, which is where the problem lies. As advised here, it's a good idea to email the package maintainer (Jeff Hallman) to request that he change the dependency to an import. That may require a bit of package reworking, so you may also suggest an short-term fix of changing the line

startYear <- as.integer(year(actualStart))

in getfame to

startYear <- as.integer(tis::year(actualStart))

(There may be other changes like this necessary.)

While you await a fix from the maintainer, you could override the function using assignInNamespace. That is, before you load the package, type

assignInNamespace(
  "getfame", 
  function(sernames, db, connection = NULL, save = FALSE, envir = parent.frame(), 
    start = NULL, end = NULL, getDoc = TRUE) 
  {
    # your fixed function definition with tis::year
  },
  "fame"
) 
Community
  • 1
  • 1
Richie Cotton
  • 118,240
  • 47
  • 247
  • 360
  • +1 Thanks a lot, I think I suggested something similar to your quick fix to him in the past. Is there anything I could do but wait for the maintainer because this is such niche product? Could you please elaborate a little bit about `assignInNamespace`? But going back to my original question: Does it mean: wait for the package maintainer is the way to go here? – Matt Bannert Oct 20 '14 at 12:39
  • Either you override `getfame` for only yourself using `assignInNamespace`, or you fork the package and maintain a copy of the whole thing (possibly publicly hosting the fork so others can use it), or you persuade the existing maintainer to fix his package. – Richie Cotton Oct 20 '14 at 13:06
  • Finally came back to this patch and made it work using your idea... so thanks a ton! The remaining problem was to hunt down several functions that were not exported from fame, so I had to fame:::functionname for all of them.. however this https://gist.github.com/mbannert/6584c3aa765648b987c3 works – Matt Bannert Feb 11 '15 at 21:14
  • looks like I was fooled by a more suitable sequence of loading packages... however it doesn't work for me yet. `assignInNamespace` assigns the namespace, if I run `fame::getfame` I see the new syntax, but if other functions simply use `getfame` without `::` the old package version function is used. How can I tell assignNamespace to really put it where all getfame calls without explizit `::` use it.... – Matt Bannert Feb 25 '15 at 16:26
  • whats really interesting is that I get the following from `getAnywhere('getfame')`: 2 differing objects matching ‘getfame’ were found in the following places package:fame namespace:fame – Matt Bannert Feb 25 '15 at 18:09