Search code examples
rlapplyr-s4

R S4class containing list of another S4class


I have an issue verifying the validity of my class 'class2'; it is made of a list of 'class1' objects. I want to verify that it is indeed the case:

class2 <- setClass(

    Class = "class2",

    slots = c(slotListName = "list"),

    validity = function(object){

             lapply(object@slotListName, function(x){

            if(!identical(is(x), "class1"))
                stop(" not a class1 object");
        });            
    });

The problem is that lapply returns values which are not accepted:

Error in validObject(.Object) : 
invalid class “class2” object: 1: NULL
invalid class “class2” object: 2: NULL

I checked that the problem was coming from the lapply by testing only the first element of the list, which is working fine:

if(!identical(is(object@slotListName[[1]]), "class1"))
       stop("not a class1 object");

I tried vectorizing but this does not change the problem.

Is there a way to verify that slotListName is indeed a list of 'class1' objects?

Thanks a lot!


Solution

  • The problem with your function is that it gives an error for an invalid object. It's supposed to return a diagnostic message, with the S4 object construction machinery taking care of the error.

    Here's how you can do it using the recommended approach, which is to define methods for initialize and setValidity. See ?setClass for more details.

    class2 <- setClass("class2", slots=c(slotListName="list"))
    
    setMethod("initialize", "class2", function(.Object, lst)
    {
        .Object@slotListName <- lst
        validObject(.Object)
        .Object
    })
    
    # returns TRUE if the object is valid, otherwise a diagnostic message
    setValidity("class2", function(object)
    {
        if(length(object@slotListName) < 1)
            "must contain at least one class1 object"
        else if(!all(sapply(object@slotListName, function(x) inherits(x, "class1"))))
            "all objects in list must be class1"
        else TRUE
    })
    
    
    ## testing
    x <- 42
    class(x) <- "class1"
    y <- 43
    class(y) <- "bad"
    
    l1 <- list(x, x, x)
    l2 <- list(x, x, y)
    
    
    ## works
    obj1 <- class2(l1)
    
    ## error: bad object in list
    obj2 <- class2(l2)
    
    ## error: empty list
    obj3 <- class2(list())