I want to set some flags in my generic (before calling UseMethod()
, I know that much :)), and then use and/or update these flags in the methods.
Like so:
g <- function(x) {
y <- 10
UseMethod("g")
}
g.default <- function(x) {
c(x = x, y = y)
}
g.a <- function(x) {
y <- 5 # update y from generic here
NextMethod()
}
This works when jumping directly to the default method:
g(structure(.Data = 1, class = "c")) # here y is never updated
# x y
# 1 10
But when I go through NextMethod()
, y
mysteriously disappears:
g(structure(.Data = 1, class = "a")) # here y is updated, but cannot be found
# Error in g.default(structure(.Data = 1, class = "a")) :
# object 'y' not found
I have figured out how to fix this, by just passing around y
a lot:
f <- function(x, ...) {
y <- 10
UseMethod("f")
}
f.default <- function(x, ..., y = 3) {
c(x = x, y = y)
}
f.a <- function(x, ...) {
y <- 5
NextMethod(y = y)
}
which yields
f(structure(.Data = 1, class = "c"))
# x y
# 1 3
f(structure(.Data = 1, class = "a"))
# x y
# 1 5
My question is: Why does NextMethod()
in the above g().*
-example kill the additional y
argument?
I thought the whole point of UseMethod()
and NextMethod()
was to pass on any and all objects from call to call, without having to manually pass them on:
NextMethod works by creating a special call frame for the next method. If no new arguments are supplied, the arguments will be the same in number, order and name as those to the current method but their values will be promises to evaluate their name in the current method and environment.
I'm particularly confused that UseMethod()
does seem to pass on y
, but NextMethod()
doesn't.
UseMethod
the quote does not say that local variables are passed. It only refers to arguments and more specifically about them being passed as promises. Passing local variables probably would decrease performance and is something unusual (why is this needed?). There is nothing killed; the content of the function environment is simply not passed. – MarguritemargyUseMethod()
andNextMethod()
behave differently.UseMethod()
does pass ony
from the content of its function environment automatically, correct (here from the generic to the default).NextMethod()
however, does not do this special trickery. – SpiersUseMethod()
andNextMethod()
in this regard? (no criticism, there may well be reasons). – SpiersNextMethod
works by creating a special call frame for the next method".UseMethod
calls the generic as a calling environment so its variables are on the search path, butNextMethod
is making some sort of separate environment, apparently. I think? – Shig(function(){x = 5; (function() x)()})()
and(function(){x = 5; eval(expression((function() x)()), envir = globalenv())})()
– Shigprint(parent.frame(n = 1))
to the method definitions you'll see that this is not the case. – Marguritemargy?parent.frame
: "Strictly, sys.parent and parent.frame refer to the context of the parent interpreted function. So [...] S3 methods can also do surprising things." – Shig