Skip to content

Defining a method in two packages

9 messages · Terry Therneau, Kevin Wright, Brian Ripley +3 more

#
The coxme package has a ranef() method, as does lme4.  I'm having
trouble getting them to play together, as shown below.  (The particular
model in the example isn't defensible, but uses a standard data set.)

The problem is that most of the time only one of lme4 or coxme will be
loaded, so each needs to define the basic ranef function as well as a
method for it.  But when loaded together the last one wins.  The coxme
object is an S3 class BTW. (Suggestions to convert it to S4 will not be
well recieved -- but that's a different and unnecessary thread.)

Odds are that this has a simple solution which I have missed.
     Terry Therneau


tmt935% R --vanilla

R version 2.10.0 (2009-10-26)
Copyright (C) 2009 The R Foundation for Statistical Computing
ISBN 3-900051-07-0

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.

  Natural language support but running in an English locale

R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.

Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.
Loading required package: survival
Loading required package: splines
Loading required package: bdsmatrix
$ph.ecog
Intercept 
0.1592346
Loading required package: Matrix
Loading required package: lattice

Attaching package: 'lme4'


        The following object(s) are masked from package:coxme :

         fixef,
         ranef
Error in function (classes, fdef, mtable)  : 
  unable to find an inherited method for function "ranef", for signature
"coxme"
#
Terry,

this happens since the ranef in coxme is a S3 generic and the one in 
lme4 is a S4 generic.

Of course, after loading lme4, you can still use the ranef from coxme:

coxme::ranef(fit)

and get the desired result.

If you write your own code, you might want to use that call explicitly 
(i.e. accessing from the correct namepsace). In your own package, you 
could simply import the generic from coxme.

Best wishes,
Uwe
On 05.03.2010 17:47, Terry Therneau wrote:
#
On Sat, 6 Mar 2010, Uwe Ligges wrote:

            
But the packages could be more cooperative.  There is also a S3 
generic for ranef in package nlme.  Ideally the S4 generic in lme4 
would have a default method which dispatched on S3 methods: that would 
be easy to achieve if there was just one other ranef, but not so if 
there are 2 or more -- but read on.

Indeed, the situation is pretty much the same if you load nlme after 
coxme:
Attaching package: 'nlme'

The following object(s) are masked from 'package:coxme':

     fixed.effects, fixef, random.effects, ranef
Error in UseMethod("ranef") :
   no applicable method for 'ranef' applied to an object of class "coxme"

The situation can be alleviated by making S3 methods visible.  Thus if
coxme exported coxme:::ranef.coxme and lme4 had a default method

function (object, ...) UseMethod("ranef")

loading lme4 (or nlme) after coxme would work.

My solution would though be NOT to reuse a name that is already 
established in another package (nlme has used it for many years).

The design problem is that generic foo() in package B might have 
nothing to do with foo() in package A.  When it does, we expect B to 
import the generic from A, but that can be a 'which came first' 
problem unless a base package is involved.  But here nlme is a 
long-established recommended package, so it would be reasonable to 
expect both coxme and lme4 to import from it.

  
    
1 day later
#
Brian & Uwe,
  Thanks for responding.  Let me see if I can refine the query and move
towards a solution.
Of course, but I'm interested in other users (as well as myself) and
prefer to avoid the 'secret handshake' form of a call.
I don't understand this.
I disagree completely.  It is precisely because of nlme and lmer
prominence that I want to reprise their methods: my users have a much
better chance of remembering how to do things.  If I followed this logic
to its conclusion one should never define a print() method because it
might conflict with the base definition.  
  The consequence is that I am under obligation to NOT make my method
something different than Doug's, if I want to satisfy the goal of user
level consistency.  Several aspects of coxme purposefully mimic lmer,
even in cases (such as print.coxme) where his layout is not precisely
what I would have chosen.

  I really do not want to require lme4 just to pick up the methods
definition.  It's a huge package, and there is no code in common.  Both
packages work very hard to be efficient via sparse matrix methods, but
the actual details are completely different due to the mathematical
structure of our underlying likelihoods.  Use of both in the same
analysis would be rare, so my issue won't be common.
I have no objection to exporting my method.  If a joint change to lme4
and coxme is the best solution, I will take the discussion off line with
Doug.  Is this the best way forward?

Terry
#
On 08.03.2010 17:16, Terry Therneau wrote:
You could import the generic from the other package and define your won 
methods for it in order to make dispatching work correctly.
Then please folow my suggestion and import the generic from the packages 
mentioned above in your namespace. Then you could extend it by your own 
methods wihtout having to define another generic of the same name and 
avoid the conflicts.
Well, then things become complicated if not impossible.
I think so.

Best wishes,
uwe
#
Wouldn't it make sense to simply create a "ranef" package whose only 
role in the universe is to create the generic function that lme4, coxme, 
and anyone else who needs it could just import, without getting tons of 
additional and (depending on the application) irrelevant code?

Best,
    Kevin
Uwe Ligges wrote:
#
I think a simpler solution, which I have implemented in lme4 but not
yet released is to have

importFrom(nlme, ranef, fixef)

in the NAMESPACE file of packages that implement methods for those
generics (and, of course, add nlme to the Imports: specification in
the DESCRIPTION file).  As nlme is a required package I don't think
this is too much of a burden.
On Tue, Mar 9, 2010 at 8:52 PM, Kevin Coombes <kevin.r.coombes at gmail.com> wrote:
#
Doug wrote:
I'll do the same change in coxme.  

We can save Kevin Coombe's solution of a separate package of "method
stubs" (which I find very similar in spirit to a shared .h file in C)
for the day that ranef/fixef gets wildly popular.  An importMethods
directive for the namespace is an intriguing long term idea for the core
team to ponder. 

Again, thanks fo all the input.  This discussion has been very
illuminating for me.

Terry T.