Christoph
Christoph

Reputation: 7063

How to use R's S3-classes together with parameters?

I fear I get something really wrong. The basics are from here and a basic (minimal) example is understood (I think) and working:

fun.default <- function(x) { # you could add further fun.class1 (works)...
  print("default")
  return(x[1] + x[2])
}

my_fun <- function(x) {
  print("my_fun")
  print(x)
  res <- UseMethod("fun", x)
  print(res)
  print("END my_fun...")
  return(res)
}
x <- c(1, 2)
my_fun(x)

However, if I want to add parameters, something goes really wrong. Form the link above:

Once UseMethod has found the correct method, it’s invoked in a special way. Rather than creating a new evaluation environment, it uses the environment of the current function call (the call to the generic), so any assignments or evaluations that were made before the call to UseMethod will be accessible to the method.

I tried all variants I could think of:

my_fun_wrong1 <- function(x, y) {
  print("my_fun_wrong1")
  print(x)
  x <- x + y
  print(x)
  res <- UseMethod("fun", x)
  print(res)
  print("END my_fun_wrong1...")
  return(res)
}
x <- c(1, 2)
# Throws: Error in fun.default(x, y = 2) : unused argument (y = 2)
my_fun_wrong1(x, y = 2)

my_fun_wrong2 <- function(x) {
  print("my_fun_wrong2")
  print(x)
  x <- x + y
  print(x)
  res <- UseMethod("fun", x)
  print(res)
  print("END my_fun_wrong2...")
  return(res)
}
x <- c(1, 2)
y = 2
# Does not throw an error, but does not give my expetced result "7": 
my_fun_wrong2(x) # wrong result!?
rm(y)

my_fun_wrong3 <- function(x, ...) {
  print("my_fun_wrong3")
  print(x)
  x <- x + y
  print(x)
  res <- UseMethod("fun", x)
  print(res)
  print("END my_fun_wrong3...")
  return(res)
}
x <- c(1, 2)
# Throws: Error in my_fun_wrong3(x, y = 2) : object 'y' not found
my_fun_wrong3(x, y = 2)

Edit after answer G. Grothendieck: Using fun.default <- function(x, ...) I get

Runs after change, but I don't understand the result:

my_fun_wrong1(x, y = 2)
[1] "my_fun_wrong1"
[1] 1 2
[1] 3 4         # Ok
[1] "default"
[1] 3           # I excpect 7

As before - I don't understand the result:

my_fun_wrong2(x) # wrong result!?
[1] "my_fun_wrong2"
[1] 1 2
[1] 3 4        # Ok!
[1] "default"
[1] 3          # 3 + 4 = 7?

Still throws an error:

my_fun_wrong3(x, y = 2)
[1] "my_fun_wrong3"
[1] 1 2
Error in my_fun_wrong3(x, y = 2) : object 'y' not found

I think, this question is really useful!

Upvotes: 1

Views: 277

Answers (1)

G. Grothendieck
G. Grothendieck

Reputation: 270448

fun.default needs ... so that the extra argument is matched.

fun.default <- function(x, ...) {
  print("default")
  return(x[1] + x[2])
}

x <- c(1, 2)
my_fun_wrong1(x, y = 2)
## [1] "my_fun_wrong1"
## [1] 1 2
## [1] 5 6
## [1] 3

Also, any statements after the call to UseMethod in the generic will not be evaluated as UseMethoddoes not return so it is pointless to put code after it in the generic.

Furthermore, you can't redefine the arguments to UseMethod. The arguments are passed on as they came in.

Suggest going over the help file ?UseMethod although admittedly it can be difficult to read.

Regarding the quote from ?UseMethod that was added to the question, this just means that the methods can access local variables defined in the function calling UseMethod. It does not mean that you can redefine arguments. Below ff.default refers to the a defined in ff.

a <- 0
ff <- function(x, ...) { a <- 1; UseMethod("ff") }
ff.default <- function(x, ...) a

ff(3)
## [1] 1

Upvotes: 2

Related Questions