[R] S4: When is validObject issued? (or why S4 is killing me:( ..

Martin Morgan mtmorgan at fhcrc.org
Sat Jun 6 00:33:01 CEST 2009


"Vitalie S." <vitosmail at rambler.ru> writes:

> Dear UseRs,
>
> Does anyone know when exactly the validity is checked in S4?
> Documentation is silent:(. 

It gets called as part of initialize,ANY-method, i.e., at the bottom
of your 'callNextMethod'. It is NOT called when there are no arguments
in addition to .Object, e.g., in a call like new("test").

> Here is a small example:
>
>  setClass("test1",representation(a="numeric"))
>  setMethod("initialize","test1",
>            function(.Object,...){
> 		a<-runif(1)  ## here  slot "a" is initialized ##
>                 callNextMethod(.Object,a=a,...)          })
>
>> new("test1")
> An object of class "test1"
> Slot "a":
> [1] 0.755
>
> #next new subclass is created with an additional slot "b":
>  setClass("test2",contains="test1",representation(b="numeric")
>           ## validity to test a==b ##
>              ,validity=function(object){
>               if(object at a!=object at b) print("values must be equal!!")
>               else TRUE
>           })
>
>  setMethod("initialize","test2",
>            function(.Object,...){
>                .Object<-callNextMethod(.Object,...)

validity is checked in the preceeding line

>                .Object at b<-.Object at a   ## here "b" is initialized ##
>
>                .Object
>            })
>
>> new("test2")
> Error in if (object at a != object at b) print("values must be equal!!")
> else TRUE : argument is of length zero
>
> This could mean only one thing, validity of "test2" is checked before
> it gets to point when b is initialized (i.e. in callNextMethod). But
> this is absurd (at leas from my point): callNextMethod constructs
> object of type "test" and should have nothing to do with validity of
> "test2". Shouldn't validity be checked only after the object is
> created?

The class of .Object is test2, and initialize should return a (valid)
instance of test2, right? So the validity check on test2 has to have
been performed before returning from callNextMethod.

> Second my slot "a" is initialized in "test1"'s constructor and "b"
> must be assigned only after the callNextMethod as in above
> code. Seemingly unsolvable paradox? How to be?

My own solution would avoid using initialize (because as you're
discovering the contract is hard to satisfy in general) and instead
use constructors

  test2 <- function(a=runif(1), b=a, ...) new("test2", a=a, b=b, ...)

or similar, which I think helps to provide a bit of an interface
between the class and it's implementation.

One could think of additional solutions (creating a new 'test' inside
'test2', and not using callNextMethod(), for instance) but this is
unlikely to be robust (e.g., when derived classes are relying on
initialize,ANY-method to fill in slots with supplied arguments).

Martin

>
> Many thanks.
>
> ______________________________________________
> R-help at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.

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

Location: Arnold Building M1 B861
Phone: (206) 667-2793




More information about the R-help mailing list