roop

how to update class globally in R without breaking CRAN rules


I am writing the function that updates database after computational work is done. I want to update the object class from c("Process") to c("Saved", "Process") for the returned object. What I am looking for is a way to this of the passed object as mutable.

class(x) <- c("Process")

save_function <- function(x){
save(x)
class(x) <- c("Saved", "Process")
x
}

y <- save_function(x) # this will assign to y, but not to x

save_function(x) # this will not reassign to x and the result is lost.

As I am writing to database, it makes sense that it should be overriden no matter if the user reassigned it or not .


Solution

  • You can do what you want but it's a bit tricky:

    x <- NA
    class(x) <- c("Process")
    
    save_function <- function(x) {
        orig_name <- deparse(substitute(x))
        class(x) <- c("Saved", "Process")
        ## assign to original symbol in *calling* environment
        assign(orig_name, x, parent.frame())
        return(x)
    }
    
    print(class(x))
    ## [1] "Process"
    y <- save_function(x)
    print(class(x))
    ## [1] "Saved"   "Process"
    

    This version both assigns the returned value to y and modifies the value of x in the original environment. If you just want to do the latter, you could return invisible(NULL)) instead (invisible() is just some sugar so that the return value isn't printed).

    <opinion>
    As commenters point out, this is not really idiomatic in R; mutable state tends to be achieved by storing objects in environments, or using one of the (many!) object orientation systems. But as long as you don't go too far down the rabbit hole, you won't get into too much trouble assigning in a different environment from time to time ...
    </opinion>