1

Many languages have special ways to handle unknown methods (examples). The one I'm most familiar with is Python's __getattr__. If someone calls a method you haven't defined for the class, __getattr__ acts as a catch-all and does something.

I've been reading up on S4 and a little on R6, but I haven't found how to do it in R. Is it possible?

Kyle Ward
  • 889
  • 1
  • 8
  • 18

2 Answers2

1

No there is no standard way of doing this from inside your class definition as you would do in python.

In python you would do something like MyObject.my_method() while in R with S3 or S4 this would be my_method(MyObject) so it looks exactly like my_function(MyObject). The only difference is that under the hood the function you called dispatches the call to the adequate method. Defining these methods for multiple classes is done as follows:

mean <- function (x, ...) UseMethod("mean", x)
mean.numeric <- function(x, ...) sum(x) / length(x)
mean.data.frame <- function(x, ...) sapply(x, mean, ...)
mean.matrix <- function(x, ...) apply(x, 2, mean)
mean.default <- function(x, ...) {
  # do something
}

However, if you call the mean function on a class for which no method has been defined, it is up to the function to handle this, not to the class.

Then you have RC and S6 objects which have a more python-like syntax (MyObject$my_method()), however they would just throw an error that there is no corresponding field or method for the class you used.

Error in envRefInferField(x, what, getClass(class(x)), selfEnv) : 
  "my_method" is not a valid field or method name for reference class “MyObject”

Here some infos about OO-programing in R.

jkd
  • 1,327
  • 14
  • 29
  • Thank you! I am correct in assuming that it works the same for S4? It seems like a lot translates over from S3 to S4. – Kyle Ward Jun 19 '19 at 20:27
  • 1
    The link above (in my answer) belongs to a page where all types of OO systems are handled, you'll find much about S4 information there and some links to even more information sources. You can make it work for S4 but in my opinion it is not as straightforward as with S3 for what you want to do. – jkd Jun 19 '19 at 20:53
  • I gave this a shot, but it's now clear to me that this handles unknown classes - not unknown methods. In this case, "mean" is a known method and 'default' is a fall back in case the class isn't numeric, data.frame, or matrix. What I'm actually looking for is to capture if someone calls "average" on my object that doesn't have an average method. – Kyle Ward Jun 19 '19 at 23:51
  • 1
    @KyleWard i edited my answer, hope it's clear now ;) – jkd Jun 20 '19 at 07:56
0

Winston Chang provided great info here:
https://github.com/r-lib/R6/issues/189#issuecomment-506405998

He explains how you can create an S3 generic function $ for your class to catch unknown methods. Read his full reply for more details, but the key function is below (Counter is the name of the class).

`$.Counter` <- function(x, name) {
  if (name %in% names(x)) {
    .subset2(x, name)
  } else {
    function(...) {
      .subset2(x, "do")(name, ...)
    }
  }
}

"If name is in the class, do that. If not, send name (and any arguments) to a function called do() defined in the class."

While I've marked this as the answer (because it solves the problem), jkd is still correct:

No there is no standard way of doing this from inside your class definition as you would do in python.

Kyle Ward
  • 889
  • 1
  • 8
  • 18
  • This is just repeating what jkd said in their answer – Hong Ooi Jun 27 '19 at 18:05
  • 2
    No, it's not repeating jkd's answer. This addresses the issue that jkd raised at the end, about not finding a corresponding field or method. – wch Jun 27 '19 at 18:39