From mtmorgan at fhcrc.org  Thu Sep 20 00:11:27 2012
From: mtmorgan at fhcrc.org (Martin Morgan)
Date: Wed, 19 Sep 2012 15:11:27 -0700
Subject: [Rd] different behavior accessing type-specific as.data.frame
 inside a function vs inside R shell
In-Reply-To: <CABWzF4XemzZQ+hL89mcf20oN17SToE+q+YL7UzGUkhMfWUmKeA@mail.gmail.com>
References: <CABWzF4XemzZQ+hL89mcf20oN17SToE+q+YL7UzGUkhMfWUmKeA@mail.gmail.com>
Message-ID: <505A430F.3080807@fhcrc.org>

Hi Brian --

On 9/19/2012 1:06 PM, brian avants wrote:
> hello
>
> we are developing an R package called ANTsR for which we have some special
> types.
>
> one of these types is an " antsMatrix " type.
>
> we implemented a "as.data.frame" function that casts an antsMatrix to a
> data.frame
>
> this works fine in a basic shell script.   for instance:
>
> # install
> R CMD INSTALL ANTsR
> # open
> R
> # in R do
> library(ANTsR)
> a <- new( "antsMatrix", "float" )
> b <- as.data.frame( a )
>
> this all works fine and i am pleased.
>
> fyi, the implementation of as.data.frame is:
>
> setMethod( f = "as.data.frame" ,
>     signature( x = "antsMatrix" ) ,
>     definition = function( x )
>            {
>    lst = .Call( "antsMatrix_asList" , x )
>   names(lst)[ 1 : (length(lst)) ] <- lst[[ length(lst) ]]
> lst[[ length(lst) ]] <- NULL
>                          as.data.frame(lst)
> }
>     )

S4 uses setAs() to establish coercion between types. "Methods for S3 
Generic Functions" of the help page ?Methods recommends defining both an 
S3 and an S4 version of the coerce method. So for this toy 
implementation of your class

   setClass("antsMatrix",
            representation=representation(values="numeric"))

I defined an S3 and an S4 coercion, reusing the S3 function as much as 
possible.

   as.data.frame.antsMatrix <-
       function(x, row.names=NULL, optional = FALSE, ...)
   {
       ## lst = .Call( "antsMatrix_asList" , x )
       ## names(lst)[ 1 : (length(lst)) ] <- lst[[ length(lst) ]]
       ## lst[[ length(lst) ]] <- NULL
       ## as.data.frame(lst)
       data.frame(values=x at values)
   }

   setAs("antsMatrix", "data.frame", function(from) {
       as.data.frame.antsMatrix(from)
   })

in the NAMESPACE file you would export both methods

   S3method(as.data.frame, antsMatrix)
   exportMethods(coerce)

This supports both forms of coercion

 > m <- new("antsMatrix", values=1:5)
 > as.data.frame(m)
   values
1      1
2      2
3      3
4      4
5      5
 > as(m, "data.frame")
   values
1      1
2      2
3      3
4      4
5      5


>
> now the problem comes when i try to access the same functionality in a
> function that is within my package R source.
>
> i.e. the function is defined in   ANTsR/R/test.R   which reads
>
> test <- function(...)
> {
>    a <- new( "antsMatrix", "float" )
>    b <- as.data.frame( a )
> }
>
> this should produce the same behavior as above, i would think.
>
> but somehow , i get different behavior:
>
> library(ANTsR)
> test()
>
> produces :
>
> Error in as.data.frame.default(a) :
>    cannot coerce class 'structure("antsMatrix", package = "ANTsR")' into a
> data.frame
>
> it is clear to me what's happening ----- R is trying to use the default
> implementation of as.data.frame
>
> which clearly won't work on an antsMatrix type.
>
> the issue is --- i do not know why R is not using the correct type-specific
> implementation when
>
> this function is called as opposed to when the same operations are called
> within the shell.
>
> certainly there must be some simple error on our part in implementation but
> i cannot find
>
> what it is --- i am the 3rd person who has looked into this.   it's true
> that we are all novice R
>
> developers .... am hoping someone on the list can provide some insight.
>
> many thanks for your time,
>
> brian
>
> 	[[alternative HTML version deleted]]
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>


-- 
Dr. Martin Morgan, PhD
Fred Hutchinson Cancer Research Center
1100 Fairview Ave. N.
PO Box 19024 Seattle, WA 98109



[Rd] different behavior accessing type-specific as.data.frame inside a function vs inside R shell
Martin Morgan