2

When defining a new reference class in R there is a bunch of boiler-plate methods that are expected (by R conventions), such as length, show etc. When these are defined they aggressively masks similar named methods/functions when called from within the class' methods. As you can not necessarily know the namespace of the foreign function it is not possible to use the package:: specifier.

Is there a way to tell a method to ignore its own methods unless called specifically using .self$?

Example:

tC <- setRefClass(
  'testClass',
  fields = list(data='list'),
  methods = list(
    length=function() {
      length(data)
    }
  )
)

example <- tC(data=list(a=1, b=2, c=3))
example$length()    # Will cause error as length is defined without arguments

Alternatively one could resort to defining S4 methods for the class instead (as reference classes are S4 classes under the hood), but this seems to be working against the reference class idea...

Edit: To avoid focusing on instances where you know the class of the data in advance consider this example:

tC <- setRefClass(
  'testClass',
  fields = list(data='list'),
  methods = list(
    length=function() {
      length(data)
    },
    combineLengths = function(otherObject) {
      .self.length() + length(otherObject)
    }
  )
)

example <- tC(data=list(a=1, b=2, c=3))
example$combineLength(rep(1, 3))    # Will cause error as length is defined without arguments

I am aware that it is possible to write your own dispatching to the correct method/function, but this seems as such a common situation that I thought it might have already been solved within the methods package (sort of the reverse of usingMethods())

My question is thus, and I apologise if this wasn't clear before: Are there ways of ignoring there reference class methods and fields within the method definitions and solely rely on .self for accessing these, so that methods/functions defined outside the class are not masked?

ThomasP85
  • 1,624
  • 2
  • 15
  • 26
  • 1
    It seems to me that you always know the namespace of a foreign function. You can see it from the help page for instance. In your example `base::length(data)` will suffice to make it work. – nicola Oct 05 '14 at 06:48
  • In the case where you know that the input is a list, yes. But imagine a situation where the user supplies the data i.e. length is not called on one of the fields, so you don't know what gets passed in. You might allow a method to accept several different objects defined in different packages. In order to use `::` you will need to examine the objects and make a manual dispatch - something R would usually do for you. – ThomasP85 Oct 05 '14 at 07:10
  • @ThomasP85 your example is not clear and your last comment also. You are using class to explicitly set the type of the data(in occurrence here is a list ) , so how you can not its type? – agstudy Oct 05 '14 at 07:16

1 Answers1

1

The example is not very clear. I don't know for what reason you can't know the namespace of your method. Whatever, here a couple of methods to work around this problem:

  1. You can use a different name for the reference class method Length with Capital "L" for example
  2. You can find dynamically the namespace of the generic function.

For example:

  methods = list(
    .show =function(data) {
      ns = sub(".*:","",getAnywhere("show")$where[1])
      func = get("show",envir = getNamespace(ns))
      func(data)
    },
    show=function() {
      .show(data)
    }
  )
  1. You can use the new reference class System R6.

For example:

tC6 <- R6Class('testClass',
  public = list(
    data=NA,
    initialize = function(data) {
      if (!missing(data)) self$data <- data
    },
    show=function()   show(self$data)
  )
)
agstudy
  • 119,832
  • 17
  • 199
  • 261