Access the generic call and user frame from within a method
Source:R/method-call.R
S7_generic_call.RdThese helpers give a method stable access to three pieces of context that are otherwise obscured by S7's dispatch machinery:
S7_generic_call()returns the call to the generic. This is useful as thecallfor an error message, so that the user sees the generic call (e.g.foo(1)) rather than S7's internal dispatch.S7_user_frame()returns the frame from which the generic was called. This is the equivalent ofparent.frame()in an S3 method, and is useful if you need non-standard evaluation.S7_generic_fun()returns the generic function itself. This is useful if you need to inspect the generic, e.g. to retrieve its name or dispatch arguments.
By default, S7_generic_call() and S7_user_frame() report the nearest call
to the generic and its caller. Set skip = "super" to skip intermediate
frames when a method re-dispatches the same generic to a superclass with
super(), reporting the outermost user-facing call and its caller.
You can also call these helpers from a function that the method calls, such
as a shared error helper; they use the innermost active method of an S7
generic. They aren't supported in methods for S3 or S4 generics, or for
operators like +.
Arguments
- match
Set to
TRUEto process withmatch.call()and name all arguments.- skip
Whether to skip calls that re-dispatch the same generic with
super(). The default,"none", reports the nearest generic call;"super"skips past these re-dispatches.
Value
S7_generic_call() returns a call; S7_user_frame() returns an
environment; S7_generic_fun() returns the generic function. All error if
called outside of a method.
See also
S7_dispatch() for how methods are called, and super() for
superclass dispatch.
Examples
# S7_generic_call() reports the call to the generic:
foo := new_generic("x")
method(foo, class_double) <- function(x) {
list(nearest = S7_generic_call(), user = S7_generic_call(skip = "super"))
}
foo(1)
#> $nearest
#> foo(1)
#>
#> $user
#> foo(1)
#>
# Set skip = "super" to skip past super() re-dispatches:
Number := new_class(parent = class_double)
method(foo, Number) <- function(x) {
foo(super(x, class_double))
}
foo(Number(1))
#> $nearest
#> foo(super(x, class_double))
#>
#> $user
#> foo(Number(1))
#>
# S7_user_frame() supplies the enclosing environment for non-standard
# evaluation, so an expression can mix columns of the data with variables
# from where the generic was called, like subset():
keep_rows := new_generic("data")
method(keep_rows, class_data.frame) <- function(data, condition) {
rows <- eval(substitute(condition), data, S7_user_frame())
data[rows, , drop = FALSE]
}
threshold <- 4
df <- data.frame(x = 1:3, y = c(2, 5, 8))
# `x` and `y` come from the data frame; `threshold` from this frame
keep_rows(df, x + y > threshold)
#> x y
#> 2 2 5
#> 3 3 8
# S7_generic_fun() returns the generic itself, e.g. to use its name in a
# message:
bar := new_generic("x")
method(bar, class_double) <- function(x) {
generic <- S7_generic_fun()
paste0("Called ", generic@name, "()")
}
bar(1)
#> [1] "Called bar()"