[R] Why 'validity' is not called? (S4)

Martin Morgan mtmorgan at fhcrc.org
Mon Oct 26 20:48:21 CET 2009


Peng Yu wrote:
> On Mon, Oct 26, 2009 at 1:49 PM, Martin Morgan <mtmorgan at fhcrc.org> wrote:
>> Peng Yu wrote:
>>> I thought that 'validity' defined in 'setClass' should be called in
>>> 'new'. Could somebody let me know why 'validity' is not called? How to
>>> make it be called?
>>>
>>>> setClass(
>>> +     Class='A',
>>> +     representation=representation(
>>> +         x='numeric'
>>> +         ),
>>> +     validity=function(object){
>>> +       cat("~~~ A: inspector ~~~\n")
>>> +       if(object at x<0){
>>> +         stop("[A:validation] object at x<0")
>>> +       }
>>> +       return(T)
>>> +     }
>>> +     )
>>> [1] "A"
>>>> setMethod(
>>> +     f='initialize',
>>> +     signature='A',
>>> +     definition=function(.Object,x){
>>> +       cat("~~~ A: initializator ~~~\n")
>>> +       .Object at x=x
>>> +       return(.Object)
>>> +     }
>>> +     )
>>> [1] "initialize"
>> The default initialize method (initialize,ANY-method) performs simple
>> slot assignment and then calls validObject. You do not call the default
>> method, so do not get slot assignment or validity checking. If you want
>> only to initialize slots as above, then do not write any initialize
>> method; let initialize,ANY-method do the work for you. Otherwise, use a
>> paradigm like
>>
>>   .Object <- callNextMethod(.Object, x=x, ...)
>>
>> in your initialize method, so that the slot x is assigned and validity
>> checked by the 'next' (eventually, initialize,ANY) method. Note that
>> validity is checked in callNextMethod, so that the object has to be
>> 'valid' after x has been assigned to it's slot.
> 
> I'm not clear what you mean by 'initialize,ANY-method'. Would you
> please give an example based my test case in the original post?

selectMethod(initialize, signature="ANY")

is the 'initialize' method applied to an object of class 'ANY' --
initialize,ANY-method (you'll see that this is how methods are
documented, with the tag \alias{initialize,A-method} for a method
initialize defined on class A). Almost all objects derive from class
'ANY', so this method is the default initialize method. Note that 'new'
creates an instance of the class, and then calls initiailize() on that
instance.

So in a new R session

  setClass('A', representation=representation(x='numeric'))

followed by

  new('A', x=1)

will result in a call to initialize(<instance of A>, x=1). You have not
defined an initialize method for the class, so dispatch takes us to
initialize,ANY-method, which fills the slots, checks validty, and returns.

When you write

setMethod(initialize, "A", function(.Object, x, ...) {
   <code here>
})

you've changed the dispatch, and now new("A", x=1) will end up in your
method. With

setMethod(initialize, "A", function(.Object, x, ...) {
   callNextMethod(.Object, x=x, ...)
})

you call the 'next' method for instances of class 'A', which will
eventually be initialize,ANY-method.

Don't know if that's any clearer.

> 
>> It is also possible to call validObject explicitly as part of your own
>> initialize method.
>>
>> Two other issues. Calling new("A") with no arguments does NOT call
>> validObject, so the default object (e.g., from the prototype argument)
>> must be valid a priori. It may be useful to define a constructor A <-
>> function(...) new("A", ...) both to provide a nicer interface to the
>> user and to map between arguments the user might find convenient and
>> slots the class wants to store.
> 
> I also don't quite understand these two issues. Would you please give
> me some examples to help me understand them? Thank you!

Here's a class that seems never to be valid

  setClass('A', representation(x='numeric'),
           validity=function(object) 'not valid')

yet

> new('A')

returns an instance because validity is not called when slots are not
assigned by initialize,ANY-method; it is presumed that the author of the
class has created a valid object prototype.

Maybe it's computationally efficient to store the data in one form, but
convenient for the user to provide it in another

  setClass("A", representation=representation(area="numeric")

one could ask that the user call

  new("A", length=1, width=2)

and write an appropriate initialize method, or one could write a constructor

A <- function(length=1, width=2, ...) new("A", area=length*width, ...)

without an explicit initialize -- let initialize,ANY-method fill the
slots. Documenting A provides the user with hints about the arguments
and a convenient interface, whereas the signature of 'new' is not
helpful. This also removes the developer from having to implement
initialize appropriately, which can get complicated. And it provides an
abstraction between interface and implementation, again generally a good
idea from an oo perspective. This is a matter of programming style, and
not an essential component of S4.

Martin

>> Martin
>>
>>>> new(Class='A', x=10)
>>> ~~~ A: initializator ~~~
>>> An object of class \u201cA\u201d
>>> Slot "x":
>>> [1] 10
>>>
>>> ______________________________________________
>>> 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
>>
> 
> ______________________________________________
> 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