Search code examples
rr6

Can you use helper functions inside R6 objects?


I'm trying to avoid repetition inside an R6 object. There are calculated/derived values that must be updated each time one of the inputs is updated.

The Cube object below demonstrates the problem. If I update any of width, height or depth, it follows that volume must be updated.

In this case, the formula is trivial, but in real-world cases that won't always be the case. It is possible to store the knowledge of volCalc someplace, and to allow set_width to use that function to update volume when they are updated?

Right now, i can create the object using the object code below:

R> cc <- Cube$new(width = 5, height = 6, depth = 7)

but it breaks on update

R> cc$set_width(10)
Error in volCalc(self$width, self$height, self$depth) : 
  could not find function "volCalc"

As you can see, I put the knowledge of how to calculate the volume of a cube (volCalc) in two places; but alas cc$set_width and friends cannot find it...

Cube <- R6Class("Cube",
  public = list(
    width = NULL,
    height = NULL,
    depth = NULL,
    volume = NULL,

    initialize = function(width, height, depth) {
      self$width <- width
      self$height <- height
      self$depth <- depth

      volCalc = function(W, H, D) W * H * D

      self$volume <- volCalc(width, height, depth)
    },

    volCalc = function(W, H, D) {
      self$volume <- W * H * D
      invisible(self)
    },    

    set_width = function(nWidth) {
      self$width <- nWidth
      volCalc(self$width, self$height, self$depth)
      invisible(self)
    },

    set_height = function(nHeight) {
      self$height <- nHeight
      volCalc(self$height, self$height, self$depth)
      invisible(self)
    },

    set_depth = function(nDepth) {
      self$depth <- nDepth
      volCalc(self$depth, self$depth, self$depth)
      invisible(self)
    }
  )
)

Solution

  • You need to tell your class where to find volCalc. It will find it in self. So all you need to do is make the internal calls to volCalc be self$volCalc. Then you can do this:

    cc <- Cube$new(width = 5, height = 6, depth = 7)
    cc
    #> <Cube>
    #>   Public:
    #>     clone: function (deep = FALSE) 
    #>     depth: 7
    #>     height: 6
    #>     initialize: function (width, height, depth) 
    #>     set_depth: function (nDepth) 
    #>     set_height: function (nHeight) 
    #>     set_width: function (nWidth) 
    #>     volCalc: function (W, H, D) 
    #>     volume: 210
    #>     width: 5
    
    cc$set_width(10)
    cc
    #> <Cube>
    #>   Public:
    #>     clone: function (deep = FALSE) 
    #>     depth: 7
    #>     height: 6
    #>     initialize: function (width, height, depth) 
    #>     set_depth: function (nDepth) 
    #>     set_height: function (nHeight) 
    #>     set_width: function (nWidth) 
    #>     volCalc: function (W, H, D) 
    #>     volume: 420
    #>     width: 10