Search code examples
rr-s4

setMethod distinguish between using to "assign" to variable and pure "info" call


Anyone know if the following can be achieved in R specifically S4

foo <- setClass("foo", contains = "matrix")
foo <- function(m = matrix(1:9, nrow = 3)) new("foo", m)

setMethod("dim", signature = "foo", 
  function(x) {
       dd <- dim([email protected])
       cat("foo dims: ")
       return(dd)
}
)

# followed by  
bar <- foo()

How or can it be achieved to distinguish between ...

dim(bar)
# which gives
foo dims: [1] 3 3 
# and calling dim to assign the return value to a variable 
# ie this call
bardims <- dim(bar)
# which does 
foo dims: 
# but I don't want it to produce any cat output to the console/screen

in the second case I would like to suppress the cat(....) part of the original "dim,foo-method". I would not mind defining something like setMethod('<-dim', 'foo', function(.... but I guess that is not available? Info: I am using R-4.0.5 here


Solution

  • It's generally not a great idea to use cat() to spit out messages in function. It gives users very little control over how they display and makes it very difficult to grab those values should they ever want them.

    A possible alternative is to annotate the response with a custom class that will output a message only when print()-ed. Hence it will not show up during assignment because those results are returned invisibly.

    Here's an S3 class that can help

    annotate_value <- function(val, msg) {
      attr(val, "message") <- msg
      class(val) <- c("annotated", class(val))
      val
    }
    print.annotated <- function(x) {
      class(x) <- setdiff(class(x), "annotated")
      cat(attr(x, "message"))
      attr(x, "message") <- NULL
      print(x)
    }
    

    And then you use it like

    
    setMethod("dim", signature = "foo", 
              function(x) {
                dd <- dim([email protected])
                annotate_value(dd, "foo dims:")
              }
    )
    

    Then when you run your code, you get the desired output

    bar <- foo()
    dim(bar)
    # foo dims:[1] 3 3
    bardims <- dim(bar)
    #