roopr-s4

What is the difference between object and .Object in OOP in R?


I'm studying S4 classes and methods and I got confused to know when to use .Object and object (using as an argument to functions on classes). I don't understand if is there any difference between them.

For example, Would be correct:

setGeneric("getTimes",function(object){standardGeneric ("getTimes")})
setMethod("getTimes","Trajectories",
          function(object){
            return(object@times)
            }
          )

or:

setGeneric("getTimes",function(.Object){standardGeneric ("getTimes")})
setMethod("getTimes","Trajectories",
          function(.Object){
            return(.Object@times)
            }
          )

Solution

  • First, you should avoid the curly braces around {standardGeneric("getTimes")}.
    The short answer for your question: there is no difference between the 2 code in your example. You were defining getTimes as a brand new generic function of your own. You can specify its arguments name whatever you like (object, x, xobject, .Object). Then, when you write the methods for the generic function, your methods' arguments name must match with the generic function's arguments name. For example:

    setGeneric("getTimes", function(object) standardGeneric("getTimes"))
    setMethod("getTimes", "Trajectories", function(object) object@times)
    

    If not follow, there will be error (technically, a warning because R automatically/"silently" correct it. However, in my opinion, R should stop and throw an error in this case):

    setGeneric("getTimes", function(object) standardGeneric("getTimes"))
    setMethod("getTimes", "Trajectories", function(x) x@times)
    # mismatch between `x` argument name in method and `object` argument name in generic
    

    In the case you want to define methods for existing generic, you should use function method.skeleton.
    Example 1:

    setGeneric("getTimes", function(xobject) standardGeneric("getTimes")) # generic function is defined
    getTimes # type function name without parentheses to get a summary of the generic
    method.skeleton("getTimes", "Trajectories", stdout())
    # copy this method skeleton to your script/source file and modify to your need  
    

    Example 2, show is a predefined generic with object as argument (see ?show) or you can type show without parentheses to check. Therefore, setMethod("show", "Trajectories", function(.Object) .Object) will be error. You can proceed using this approach, however, I think method.skeleton is a pretty useful alternative:

    > method.skeleton("show", "Trajectories", stdout())
    setMethod("show",
        signature(object = "Trajectories"),
        function (object) 
        {
            stop("need a definition for the method here")
        }
    )
    

    Example 3, initialize is a generic function and its argument .Object may be defined (type initialize without parentheses to check). From my understanding, the reason .Object is chosen as argument name in this case to invoke the feeling of a prototype object (you can read more at ?initialize). Similarly to Example 2, use the method.skeleton helper function:

    > method.skeleton("initialize", "Trajectories", stdout())
    setMethod("initialize",
        signature(.Object = "Trajectories"),
        function (.Object, ...) 
        {
            stop("need a definition for the method here")
        }
    )  
    

    Note: there is a special case for replacement/assignment function (<-), that is its last argument must be named value. Read more. For example:

    setClass("Trajectories", slots = c(times = "numeric"))
    
    setGeneric("getTimes", function(x) standardGeneric("getTimes"))
    setMethod("getTimes","Trajectories", function(x) x@times)
    
    setGeneric("getTimes<-", function(xobject, value) standardGeneric("getTimes<-"))
    setMethod("getTimes<-", c("Trajectories", "ANY"), function(xobject, value) {
        xobject@times <- value
        xobject
    })
    
    # test drive
    m <- new("Trajectories", times = 32)
    getTimes(m)
    getTimes(m) <- 42
    getTimes(m)
    

    R will not output any error or warning if you use other name (new_value in below) when defining the generic and accompanying methods. However, when you use it, R will error:

    setGeneric("getTimes<-", function(xobject, new_value) standardGeneric("getTimes<-"))
    setMethod("getTimes<-", c("Trajectories", "ANY"), function(xobject, new_value) {
        xobject@times <- new_value
        xobject
    })
    
    # test drive
    m <- new("Trajectories", times = 32)
    getTimes(m)
    getTimes(m) <- 42 # error because the right side of <- is always considered as `value` argument