f <- function() 1
g <- function() 2
class(g) <- "function"
class(f) ## "function"
class(g) ## "function"
length.function <- function(x) "function"
length(f) ## 1
length(g) ## "function"
First, length
is not a typical generic function, but rather an "Internal Generic Function". You can see this by looking at its definition:
> length
function (x) .Primitive("length")
Compare this to a typical generic function:
> print
function (x, ...)
UseMethod("print")
<bytecode: 0x116ca6f90>
<environment: namespace:base>
length
calls straight into .Primitive
which then can do dispatch if it does not handle the call itself; the typical approach is directly calling UseMethod
which only handles dispatch. Also note that there is no length.default
function because the code in the .Primitive
call does that:
> methods("length")
[1] length.function length.pdf_doc* length.POSIXlt
I am not sure it is completely defined when an Internal Generic will look at user defined methods and when it will use only internal ones; I think the general idea is that for a user/package defined (effectively, non-core) class, provided methods will be used. But overriding for internal classes may or may not work.
Additionally (though not strictly relevant for this case), even for a typical generic method, the documentation is ambiguous as to what should happen when the class is derived implicitly rather than given as an attribute. First, what class()
reports is an amalgamation of things. From the class
help page:
Many R objects have a
class
attribute, a character vector giving the names of the classes from which the object inherits. If the object does not have a class attribute, it has an implicit class,"matrix"
,"array"
or the result ofmode(x)
(except that integer vectors have implicit class"integer"
).
So despite class
returning the same thing for f
and g
, they are not the same.
> attributes(f)
$srcref
function() 1
> attributes(g)
$srcref
function() 2
$class
[1] "function"
Now, here is where it gets ambiguous. Method dispatch is talked about in (at least) 2 places: the class
help page and the UseMethod
help page. UseMethod
says:
When a function calling
UseMethod("fun")
is applied to an object with class attributec("first", "second")
, the system searches for a function calledfun.first
and, if it finds it, applies it to the object. If no such function is found a function calledfun.second
is tried. If no class name produces a suitable function, the functionfun.default
is used, if it exists, or an error results.
While class
says:
When a generic function fun is applied to an object with class attribute
c("first", "second")
, the system searches for a function calledfun.first
and, if it finds it, applies it to the object. If no such function is found, a function calledfun.second
is tried. If no class name produces a suitable function, the functionfun.default
is used (if it exists). If there is no class attribute, the implicit class is tried, then the default method.
The real difference is in the last sentence that the class
page has that UseMethod
doesn't. UseMethod
does not say what happens if there is no class
attribute; class
says that the implicit class is used to dispatch. Your code seems to indicate that what is documented in class
is not correct, as length.function
would have been called for g
were it.
What really happens in method dispatch when there is no class attribute will probably require examining the source code as the documentation does not seem to help.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With