Canadian_Marine
Canadian_Marine

Reputation: 539

R ReferenceClass: Call parent method in child object definition

I'm trying to implement object-specific method caching in R. I have many different kinds of objects, and many of them implement functions that get called often, take a long time to run, and whose inputs/outputs don't change between executions. So to save time, I want to cache the outputs of these methods to a hash-map, which maps the hash of the parameter inputs to the output. The catch is that these long-running methods reference the object fields, which means that I need the caching to be object-specific. I can't implement a global caching process, because executing the same function on two different instances of the same object typically produces different outputs.

To do this, I've implemented a parent class Cache, which has a hash-map, and implements the 'cache' function. This object can then be inherited by other objects to easily implement object-specific method-caching.

In order to streamline the process, I've also implemented a decorator, so that the methods of the child objects can be easily wrapped in the caching function.

Here's my code:

# Define the infix decorator function
`%decorate%` = function(decorator, f) {
  decorator(f)
}


# Cache parent class
Cache = 
  # ----
  setRefClass(
    'Cache',
    fields = 
      c(  
        # PRIVATE: hash map of inputs to outputs
        "prev_output_hash_map__"
      ),
    methods = 
      list(
        # Initialize the private values.
        initialize =
          function(...) {
            callSuper(
              prev_output_hash_map__ = r2r::hashmap(),
              ...
            )
          },

        cache =
          function(f) {
            function(refresh = F,...) {              

              # Hash the function name and it's inputs
              input_hash__ =
                rlang::hash(
                  list(
                    deparse1(f), # The code of the function
                    ... # The parameter inputs to the function
                  )
                )
              # Check to see if the input hash is present in the hash map
              # If it isn't execute the inner function and save the results
              if(is.null(prev_output_hash_map__[input_hash__][[1]]) | refresh) {
                prev_output_hash_map__[[input_hash__]] <<- f(...)
              }
              # Return the previously saved output
              return(prev_output_hash_map__[input_hash__][[1]])

            }
          }
      )
  )

# Child class which will implement caching on one or more of its methods
CachingObject = 
  setRefClass(
    "CachingObject",
    contains = "Cache",
    methods = 
      list(
        # A long-running method that I want to cache the output of
        long_running_function = 
          cache %decorate% function(input1, input2) {
            Sys.sleep(10)
            return(input1 + input2)
          }
      )
  )

I've verified that the caching logic works correctly outside of the reference class. The problem here is that the 'cache' function is a method of the Cache object, and not defined in the global environment. This means that the method isn't visible when the child object CachingObject is being defined, and I get the following error:

Error in cache %decorate% function(input1, input2) { : 
object 'cache' not found

Is there some way to reference the methods of a parent object in the midst of the definition of a child object? If not, is there a way to accomplish what I'm trying to do here?

Upvotes: 1

Views: 48

Answers (0)

Related Questions