[R] inheritence in S4

Christophe Genolini cgenolin at u-paris10.fr
Thu Mar 6 00:40:23 CET 2008


Hi Martin

I was not that much speaking about what we can do, but more about what 
we can't. We can't decide that object will be 'never empty', we have to 
allow empty oject, otherwise new("A") will not work and that will be 
problematic.

So, at this point, I see :
  - it is necessary to allow the creation of empty object (otherwise, we 
are in trouble with 'as')
  - so 'new' will have to create object either empty or valid.
  - 'initialize' can check if an object is valid but has first to check 
if the object is non empty
  - I create an object Ccc containing an object Aaa : If Ccc is calling 
the constructor of Aaa, then initialize of Aaa ic called. If Ccc is 
setting the Aaa slot one bu one, the initialize of Aaa is not caller.
  - In addition, I did not speak about the setteur, but the 'setSlotX 
<-' does not call the initialize. So we have to check the validity of 
the object after any 'setSlot' again.

In consequence, to program as safe as possible:
  - for checking if an object is valid or not, I am thinking of setting 
a method checkCoherance
  - 'initialize' will just set slot to either empty or some value, then 
call checkCoherance
  - 'setSlotX<-' will change slot X, then call checkCoherance
  - If I create a C object, its checkCoherance method will call 
checkCoherance(as(object,"A"))

Here is an example (still the same stupid example with a single slot. 
Obviously, it has no interest on so small object, it is just to simplify)

--- 8< ------------------
setGeneric("checkCoherance",function(object){standardGeneric("checkCoherance")})

setClass("A", representation(x="numeric"))
setMethod("checkCoherance","A",
    function(object){
        cat("*** checkCoherance A ***\n")
        if(length(object at x)>0){
            if(object at x<0){stop("Object incoherance : x should be 
positive")}else{}
        }else{}
        return(TRUE)
    }
)

setMethod("initialize","A",
    function(.Object,value=numeric(0)){
        cat("*** initialize A ***\n")
        .Object at x <- value
        checkCoherance(.Object)
        return(.Object)
    }
)

setGeneric("setX<-",function(object,value){standardGeneric("setX<-")})
setReplaceMethod("setX","A",
  function(object,value){
    object at x <- value
    checkCoherance(object)
    return(object)
  }
)
 
a1 <- new("A")
a2 <- new("A",value=4)
try(a3 <- new("A",value=-4))

A <- function(val=numeric(0)){
  new("A",value=val)
}
A()
A(val=4)
A(val=-4)

setClass("C", representation(y="numeric"),contains="A")
setMethod("checkCoherance","C",
    function(object){
        cat("*** checkCoherance C ***\n")
        if(length(object at y)>0){
            if(object at y>0){stop("Object incoherance : y should be 
négative")}else{}
        }else{}
        checkCoherance(as(object,"A"))
        return(TRUE)
    }
)
setMethod("initialize","C",
    function(.Object,valueX=numeric(0), valueY=numeric(0)){
        cat("*** initialize C ***\n")
        .Object at x <- valueX
        .Object at y <- valueY
        checkCoherance(.Object)
        return(.Object)
    }
)

c <- new("C",valueX=10,valueY=12)
new("C")

C <- function(valX=numeric(0),valY=numeric(0)){
   new("C",valueX=valX,valueY=valY)
}
C()
C(valX=5)
try(C(valX=-5))
C(valY=-3)
c1 <- C(valX=4,valY=-6)
as(c1,"A")

--- 8< ------------------
> You're partly misunderstanding...
>
>   
Lol. I guess so, and unfortunatly, it is not over ...
> setClass("A", representation(x="numeric"),
>     prototype=prototype(x=0))
>
>   
I do not understand the difference with

setClass("A", representation(x="numeric"),
    prototype(x=0)
)


> If you have an initialize
> method on "A" then it will be called. 
Only if you call the A constructor, right ? Not if you set the slot that 
C has heritate from A one by one, right ?

Christophe



More information about the R-help mailing list