1

In R, I wish to declare a new S3 class, and then define methods for it in two packages.

Currently, this works fine for one package, but the second package to load masks the first, an then the class methods for package one are not found (and it ends up calling the .default method.

Asked on devotees google list, and got the working solution from Hadley to create a third package, declare the base class there, then import and export that namespace in the two real packages. But I'd really rather not use a third package...

Any suggestions? (not this is all being built with devtools, which treats S3 objects appropriately, based on the . in the function name)

For those not familiar with S3, you declare a default handler, class handlers, and a stub function which figures out a class handler exists, and if not calls the default handler.

So, in package1, I define and export a base class, some useful handlers, and a default.

#' @export
#' myFun <- function(x, ...){
#'  UseMethod("myFun", x)
#' }

#' @export
#' myFun.x1 <- function(x, ...){
#'  message("hi, I handled an x1 object from package 1")
#' }

#' @export
#' myFun.default <- function(x,...){
#'  print("myFun is not defined")
#'}

In package 2, I wish just to define and export some additional object handlers

#' @export
#' myFun.x2 <- function(x, ...){
#'  message("hi, I handled an x2 object from package 2")
#' }

The second package depends on the several fns in package 1, so I depend on it in the DESCRIPTION file:

Depends:
    packageOne

FYI, if I import packageOne, I get the error Error : object 'myFun' not found whilst loading namespace 'packageTwo'

Depending on package1 ensures that it is loaded and available whenever package2 is loaded, but R's resolve chain seems only to look in which ever package loads last for handlers. Calling an S3 function for an object with a handler in package 1 works fine. But if the handler is defined in package2, the lookup table fails to find a handler in package 2, and calls default in package 1.

I guess I could write a myFun.defaul handler in package 2 which explicitly calls package1's version of myFun. Suggestions welcomed

#' @export
#' myFun.default <- function(x,...){
#'    package1::myfun(x, ...)
#'}

perhaps that will work

Community
  • 1
  • 1
tim
  • 3,559
  • 1
  • 33
  • 46
  • Just a guess, and doubt I'm going to do better than Hadley, but why not have the second package declare dependence on the first? – Carl Witthoft Jan 22 '15 at 19:43
  • 1
    Your question really isn't that clear, since you don't say what's declared in each package. My guess is that you need to declare the generic in one package and make sure packages with methods import the generic. – Joshua Ulrich Jan 22 '15 at 19:46
  • You can make `umx.default` default to the other package. – Tyler Rinker Jan 22 '15 at 20:03
  • @TylerRinker That sounds like a start, but also a cycle: they'll just call each other, no? – tim Jan 22 '15 at 20:17
  • @JoshuaUlrich: editing Q now... I started by declaring the generic in one, didn't work as R didn't find the function for one package. Declared generic in both only works for the last-loaded package. I will also add what I am doing re namespace import to clarify. – tim Jan 22 '15 at 20:20
  • 1
    It's still not clear what's in each package, or if the methods are registered. And Depends != Imports. – Joshua Ulrich Jan 22 '15 at 21:16
  • @JoshuaUlrich Nice catch - tried import: that breaks loading packageTwo (see edit in question). :-( – tim Jan 23 '15 at 15:39
  • For the third time, it's not clear what's in each package, whether or not methods are registered, and now it's not clear how you tried to import. You would be much more likely to get decent help if you took the time to give an explicit (and possibly reproducible) example of what you're doing. Vague descriptions don't help anyone help you. – Joshua Ulrich Jan 23 '15 at 15:44
  • I was hoping someone would have a recipe for how to do it, rather than have to figure out from what I am doing what the problem might be. A repro example will require people building multiple packages... What does it mean to "register" a method? Now it is clear that I was depending, and that importing breaks the build process, unless i redeclare the function in the second package... – tim Jan 24 '15 at 16:42

0 Answers0