Question

I have a question about the Reference Classes. How can I check the field assignments.

Here my sample code:

rm(list=ls(all=TRUE))

setRefClass(
    Class = "A", 
    fields = list(firstValue = "numeric"),
    methods = list(

        initialize = function(..., firstValue = numeric()) {
            setFirstValue(firstValue)
        },

        getFirstValue = function() {
            return(firstValue)
        },

        setFirstValue = function(value) {
            if(length(value) != 0) {
                if(value > 10) {
                    cat("only values lower 10 allowed!\n")
                    firstValue <<- 10
                } else {
                    firstValue <<- value
                }
            } else {
                firstValue <<- 0
            }
        }               
    )
)

test <- getRefClass("A")$new()
test$getFirstValue()
test$firstValue
test$setFirstValue(11)
test$firstValue
test$firstValue <- 11
test$firstValue

My problem is how can I prevent it, that "test$firstValue <- 11" is set without to check the value. In S4, I would solve it like this:

setGeneric(name = 'setFirstValue<-', def = function(object, value) {standardGeneric('setFirstValue<-')})
setReplaceMethod(
        f = 'setFirstValue',
        signature = 'A',
        definition = function(object, value) {
            object@.firstValue <- value
            validObject(object)
            return(object)
        }
)

and

setReplaceMethod(
    f = "[",
    signature = "A",
    definition = function(x, i ,j , value) {
        if(i == 'firstValue ' || i == 1) {setFirstValue(x) <- value}
    return(x)
    }
)

Finally, in the class definition of "A" the "validity = function(object){ ... }" would be placed. But how I can resolve this with Reference Classes?

Thanks for help.

Was it helpful?

Solution

setValidity and explicit calls to validObject can be used on reference classes, too,

A <- setRefClass("A", fields=list(x="numeric"))

setValidity("A", function(object) {
    if (length(object$x) != 1L || !all(object$x < 11))
        "'x' must be length 1 and < 11"
    else NULL
})

and then

> a = A(x=11)
> validObject(a)
Error in validObject(a) : 
  invalid class "A" object: 'x' must be length 1 and < 11

but in some ways your direct field access is the same as direct slot access

B <- setClass("B", representation(x="numeric"))

setValidity("B", function(object) {
    if (length(object@x) != 1L || !all(object@x < 11))
        "'x' must be length 1 and < 11"
    else NULL
})

with

> b = B()
> b@x = 11       # no validObject check, just like direct field assignment
> validObject(b)
Error in validObject(b) : 
  invalid class "B" object: 'x' must be length 1 and < 11

So as a programming discipline using the accessor that you've defined, test$setFirstValue(11), seems to be the best approach to imposing additional validity conditions.

S4 classes have the usual semantics of R -- appearance of copy on change -- whereas reference classes have reference semantics; this is the main difference and driving force in determining appropriate class system to use, even though performance differences are also present.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top