From jmc at r-project.org  Thu Apr 10 00:20:30 2008
From: jmc at r-project.org (John Chambers)
Date: Wed, 09 Apr 2008 15:20:30 -0700
Subject: [Rd] coerce methods and inheritance
In-Reply-To: <47FD11E6.1090901@fhcrc.org>
References: <47FD11E6.1090901@fhcrc.org>
Message-ID: <47FD412E.1010609@r-project.org>

Herve Pages wrote:
> Hi,
>
> It doesn't seem that the dispatching algo is finding my coerce method under
> some circumstances.
> Let's say I have 2 classes, A and AA and that AA is just a direct extension
> of A with no additional slots:
>
>    setClass("A", representation(ii="integer"))
>    setClass("AA", contains="A")
>
> I can define a method for coercing my objects to an integer vector with:
>
>    setAs("A", "integer", function(from) {cat("I'm the A->integer coerce method\n"); from at ii})
>
> and this works as expected when my object is an AA instance:
>
>    > aa <- new("AA", ii=sample(10, 5))
>    > as(aa, "integer")
>    I'm the A->integer coerce method
>    [1] 10  1  6  4  7
>
> But things don't behave that way anymore if I introduce a direct extension of AA:
>
>    setClass("OrderedAA",
>      contains="AA",
>      validity=function(object)
>      {
>          if (!all(diff(object at ii) >= 0))
>              return("slot 'ii' is not ordered")
>          TRUE
>      }
>    )
>
> and a method for coercing an A object to an OrderedAA object:
>
>    setAs("A", "OrderedAA",
>      function(from)
>      {
>          cat("I'm the A->OrderedAA coerce method\n")
>          new("OrderedAA", ii=sort(from at ii))
>      }
>    )
>
> My A->OrderedAA coerce method is not called anymore:
>
>    > oaa <- as(aa, "OrderedAA")
>    > oaa
>    > validObject(oaa)
>    Error in validObject(oaa) :
>      invalid class "OrderedAA" object: slot 'ii' is not ordered
>
> This looks like a bug to me.
>   
Well, obscure perhaps, and not as well documented as it might be.

Defining a subclass of "AA" creates implicit coerce methods in both 
directions.  The method from "AA" to its subclass creates a new object 
from the subclass, then inserts the inherited slots.

 > selectMethod("coerce", c("AA", "OrderedAA"))
Method Definition:

function (from, to)
{
    obj <- new("OrderedAA")
    as(obj, "AA") <- from
    obj
}

Signatures:
        from to        
target  "AA" "OrderedAA"
defined "AA" "OrderedAA"

The situation is made more confusing because these methods are only 
explicitly inserted in the coerce() function the first time they're used 
(for obvious efficiency reasons).

Notice that this is a direct method, not an inherited one.  It will be 
chosen by the method selection from as().

So it is true that if you want to override the implicit methods, you 
have to do that for each new subclass, presumably when defining the 
subclass.

 >    setAs("AA", "OrderedAA",
+      function(from)
+      {
+          cat("I'm the A->OrderedAA coerce method\n")
+          new("OrderedAA", ii=sor .... [TRUNCATED]
 > as(aa, "OrderedAA")
I'm the A->OrderedAA coerce method
An object of class "OrderedAA"
Slot "ii":
[1]  4  5  7  8 10

It's possible to argue that an inherited, explicitly defined method, as 
in your case, is worth more than a direct, implicitly defined method.  
But whether this would be true in all applications is not obvious.

But that the documentation needs to spell this out--no question.  Thanks 
for bringing it up.

John


> Thanks,
> H.
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>
>



[Rd] coerce methods and inheritance
John Chambers