Search code examples
rr-s4

What is setReplaceMethod() and how does it work?


I'm confused about the usage of setReplaceMethod(). Looking at ?setReplaceMethod does not provide an explanation and Googling is less than helpful.

QUESTION : Please explain setReplaceMethod(), it's usage and how it works (preferably with an example).


Solution

  • Here is what I found. As pointed by @Hong Ooi in the comments setReplaceMethod("fun") is the same as setMethod("fun<-"), so setReplaceMethod is used to create a method for a generic replacement function in the S4 object system of R.

    What is a replacement function is explained in what-are-replacement-functions-in-r. Very rougly, if you have a function called fun<-, because its name ends with <-, you can write fun(x)<-a and R will read x <- "fun<-"(x,a).

    The S4 object system is described in S4 - Advanced R.

    To give an example maybe it is easier to start by creating a method for an S4 generic function, which is not a replacement function:

    ## Define an S4 class 'Polygon' and an object of this class
    setClass("Polygon", representation(sides = "integer"))
    p1 <- new("Polygon", sides = 33L)
    ## Define a generic S4 function 'sides'
    sides <- function(object){ NA }
    setGeneric("sides")
    ## sides returns NA
    sides( p1 )
    ## Define a method for 'sides' for the class 'Polygon'
    setMethod("sides", signature(object = "Polygon"), function(object) {
      object@sides
    })
    ## Now sides returns the sides of p1
    sides( p1 )
    

    Creating a method for a generic replacement function is similar:

    ## Define a generic replacement function 'sides<-'
    "sides<-" <- function(object, value){ object }
    setGeneric( "sides<-" )
    ## The generic 'sides<-' doesn't change the object
    sides( p1 ) <- 12L
    sides( p1 )
    ## Define a method for 'sides<-' for the class 'Polygon',
    ## setting the value of the 'sides' slot
    setMethod( "sides<-", signature(object = "Polygon"), function(object, value) {
      object@sides <- value
      object
    })
    ## Now 'sides<-' change the sides of p1
    sides( p1 ) <- 12L
    sides( p1 )
    

    You asked also about $<-. My guess is this: x$name<-value is interpreted as "$"(x,name)<-value and then as x <- "$<-"(x,name,value). Note that a generic function $<- is already defined (isGeneric("$<-")), so we only define a method for our class Polygon:

    setMethod( "$<-", signature(x = "Polygon"), function(x, name, value) {
      if( name=="sides" ){
        x@sides <- value
      }
      x
    })
    ## Nothing changes if we try to set 'faces'
    p1$faces <- 3L
    p1
    ## but we can set the 'sides'
    p1$sides <- 3L
    p1
    

    Note that the arguments x, name and value are dictated by the generic.