Search code examples
rr6

Good practice to define print() for R6 in R?


I want to modify print() for my R6 class so that if field dt is still NULL, it print the entire Class information, as done by default. However, when dt is NOT NULL, then it only prints dt, like in example below. How to do that?

library(R6)
Simple <- R6Class(
  "Simple", 
  portable = F, # for convenience so that I can use either dt or self$dt in class functions
  public = list(
    x=1, y=2, 
    dt = NULL,
    print = function (...) {
      if (is.null(dt)){
        print(...)
      } else {
        print(self$dt)
      }
    },
    date="2020-10-10"
  )
)
s <- Simple$new()
s
# I WANT THIS TO BE PRINTEED
# <Simple>
#   Public:
#   clone: function (deep = FALSE) 
#     date: 2020-10-10
#     dt: NULL
#     x: 1
#     y: 2
s$dt <- mtcars
s
# WILL PRINT mtcars

Solution

  • When you type s into the console, you invoke the (S3) generic print function, which dispatches R6:::print.R6. If you look at what R6:::print.R6 does, it searches for a member function of the object called "print", and if it is present, it uses that to print the object.

    If a print method has not been defined for the R6 object, then R6:::print.R6 will use R6:::format.R6 to display the R6 object. This is what you want to see when dt is NULL.

    You will need to do the same within your print method, since the act of defining a print method within your class prevents this behaviour.

    Fortunately, this is straightforward:

    library(R6)
    
    Simple <- R6Class(
      "Simple",
      public = list(
        x = 1, y = 2, 
        dt = NULL,
        print = function (...) {
          if (is.null(self$dt)){
            cat(format(self, ...), sep = "\n")
          } else {
            print(self$dt)
          }
        },
        date="2020-10-10"
      )
    )
    
    s <- Simple$new()
    s
    #> <Simple>
    #>   Public:
    #>     clone: function (deep = FALSE) 
    #>     date: 2020-10-10
    #>     dt: NULL
    #>     print: function (...) 
    #>     x: 1
    #>     y: 2
    
    s$dt <- 'Dt content only'
    s
    #> [1] "Dt content only"
    

    Created on 2023-02-09 with reprex v2.0.2