This is a surprisingly subtle and complex question.
The reason why base::`[.factor`(ff)
doesn't work and `[.factor`(ff)`
does even though both pieces of code literally invoke the same function is because of the unusual way in NextMethod
works. The TL;DR is that `[.factor`
is s symbol, but base::`[.factor`
is a call.
When you invoke NextMethod
, the underlying C code works out what context it was called in, and will throw an error if any of several conditions aren't met.
One of these conditions is that the function in which NextMethod
resides has to have been called directly - in technical terms, the first node in the call has to be a symbol, not an expression. If you try to get the function via a call, NextMethod
will detect that and give you the "anonymous function" error.
NextMethod
also checks that the name of the function is consistent with the generic being used, and if there is a mismatch, we get the "wrong value for .Method
" error
We can demonstrate identical behaviour with a simple example. We have an object of class "foo":
foo <- structure(1:3, class = c("foo"))
foo
#> [1] 1 2 3
#> attr(,"class")
#> [1] "foo"
We want to be able to subset a "foo" so that any subset of a "foo" is still of class "foo", but otherwise we want the exact same subsetting rules as a numeric vector. This is where NextMethod
comes in:
`[.foo` <- function(obj, ind) {
y <- NextMethod("[")
class(y) <- "foo"
y
}
foo[2]
#> [1] 2
#> attr(,"class")
#> [1] "foo"
This works as expected, and so does calling it directly:
`[.foo`(foo, 2)
#> [1] 2
But, if we try to call the function indirectly, say via get
, then NextMethod
throws the error because get("[.foo")
is a call, not a symbol.
get("[.foo")(foo, 2)
#> Error in NextMethod("[") : 'NextMethod' called from an anonymous function
Even wrapping the call in parentheses or curly brackets is enough to generate the error (because these brackets are actually calls too)
(`[.foo`)(foo, 2)
#> Error in NextMethod("[") : 'NextMethod' called from an anonymous function
{`[.foo`}(foo, 2)
#> Error in NextMethod("[") : 'NextMethod' called from an anonymous function
If we try to rename the function, we get the same error you did with trying to rename [.factor
:
f <- `[.foo`
f(foo, 2)
#> Error in NextMethod("[") : wrong value for .Method
Now f
is at least a symbol, but it is the wrong symbol (f
is not [
)
The final piece of the puzzle is why base::`[.factor`
isn't a symbol. It's because in R the namespace symbol ::
is actually a call, so base::`[.factor`
is actually parsed as `::`(base, `[.factor`)
class(quote(base::`[.factor`))
#> [1] "call"
Whereas, without the namespace identifier, what we have is a symbol (a.k.a. "name")
class(quote(`[.factor`))
#> [1] "name"