I've noticed that when I call args
on some of the primitive functions, byte-codes show up as well. But on other primitives, no byte-code appears. For example
args(length)
# function (x)
# NULL
args(list)
# function (...)
# NULL
# <bytecode: 0x44a0f38>
Why is that?
At first I thought it might be related to the ...
argument, but the following disproves that theory.
args(dim)
# function (x)
# NULL
args(unclass)
# function (x)
# NULL
# <bytecode: 0x44a0450>
It's confusing to me that a byte-code only shows up in some of these, and not in others. I have always been under the impression that all primitives are special and that they all share the same "attributes" (for lack of a better word, not the actual R attributes).
As agstudy noted, this is an oddity related to how args
prints things. That is, whether args
includes a bytecode line in its output isn't a reliable indicator of whether or not the function was byte compiled. compare:
args(writeLines)
## function (text, con = stdout(), sep = "\n", useBytes = FALSE)
## NULL
writeLines
## function (text, con = stdout(), sep = "\n", useBytes = FALSE)
## {
## if (is.character(con)) {
## con <- file(con, "w")
## on.exit(close(con))
## }
## .Internal(writeLines(text, con, sep, useBytes))
## }
## <bytecode: 0x000000001bf3aeb0>
We can compare printing of a bytecode line for args
vs. standard function printing.
arg_shows_bytecode <- function(fn)
{
output <- capture.output(args(fn))
grepl("^<bytecode", output[length(output)])
}
printing_shows_bytecode <- function(fn)
{
output <- capture.output(print(fn))
length(output) > 1 && grepl("^<bytecode", output[length(output) - 1])
}
base_fns <- Filter(is.function, mget(ls(baseenv()), baseenv()))
yn_args <- vapply(base_fns, arg_shows_bytecode, logical(1))
yn_print <- vapply(base_fns, printing_shows_bytecode, logical(1))
It's worth noting that all functions where args
shows bytecode information are primitives.
head(base_fns[yn_args])
## $`%*%`
## function (x, y) .Primitive("%*%")
##
## $as.call
## function (x) .Primitive("as.call")
##
## $attr
## function (x, which, exact = FALSE) .Primitive("attr")
##
## $`attr<-`
## function (x, which, value) .Primitive("attr<-")
##
## $attributes
## function (obj) .Primitive("attributes")
##
## $`attributes<-`
## function (obj, value) .Primitive("attributes<-")
The converse isn't true: some base functions where args
doesn't show bytecode information are primitives; others are not.
yn_prim <- vapply(base_fns, is.primitive, logical(1))
table(yn_args, yn_print, yn_prim)
## , , yn_prim = FALSE
##
## yn_print
## yn_args FALSE TRUE
## FALSE 0 988
## TRUE 0 0
##
## , , yn_prim = TRUE
##
## yn_print
## yn_args FALSE TRUE
## FALSE 119 0
## TRUE 63 0
So non-primitive functions in the base package are all compiled, but args
doesn't mention it. Primitive functions don't show a bytecode message when printed, and only sometimes show a bytecode message when called with args.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments