[R] Validity check when setting slot

Martin Maechler
2009-08-10T16:25:22Z

>>>>> "RG" == Renaud Gaujoux <renaud at
mancala.cbio.uct.ac.za>
>>>>>     on Mon, 10 Aug 2009 17:19:12 +0200 (SAST) writes:

    RG> Hi,
    RG> I'm wondering if the following behaviour is normal:

    RG> setClass('A', representation(number='numeric'),
    RG> validity=function(object){
    RG> if( object at number < -1 ) return("Invalid number");
TRUE})
    >> [1] "A"
    RG> a <- new('A')
    RG> a
    >> An object of class ?A?
    >> Slot "number":
    >> numeric(0)

    RG> a at number <- 0
    RG> a at number <- -3
    RG> a
    >> An object of class ?A?
    >> Slot "number":
    >> [1] -3

However, note that

 > validObject(a)
 Error in validObject(a) : invalid class "A" object: Invalid number

and also

 > a at number <- "foo"
 Error in checkSlotAssignment(object, name, value) :
   assignment of an object of class "character" is not valid for slot
"number" in an object of class "A"; is(value,
"numeric") is not TRUE
 Calls: @<- -> slot<- -> checkSlotAssignment



    RG> So: the slot is set to an invalid value according to the validity
method
    RG> and nothing happens (no error) whereas the doc says:

    RG> "The replacement forms do check (except for
    RG> 'slot' in the case 'check=FALSE').  So long as slots
are set
    RG> without cheating, the extracted slots will be valid."

hmm, I don't where that part is cited from,
but yes, the above *is* correct behavior.

Why?
Well, several reasons:
1)  slot assignment must be reasonably efficient, as it is an
   "atomic" part of building up high level objects
    ==> only the *class* of the slot is checked, but not the
    validity method of the container.
2) During the incremental build-up of an S4 object (with several
   slots), the object itself is often not "valid"; it would be
   bad, if slot-assignment triggered "upper-level" validity checking.


If you really want what you want (:-),
use something like

setClass("posNumber", contains = "numeric",
         validity = function(object) {
             if(object <= 0) return("Not a positive number")
             TRUE
         })

setClass('B', representation(number= 'posNumber'))

(b <- new("B", number = new("posNumber",pi)))
## An object of class 'B'
## Slot "number":
## An object of class 'posNumber'
## [1] 3.141593

b at number <- -2
## Error in checkSlotAssignment .........


Regards,
Martin

    RG> Thanks,
    RG> Renaud

    >> sessionInfo()
    RG> R version 2.9.1 (2009-06-26)
    ..........