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.
Thanks for the report. This behavior is unintentional (a bug, as Hadley says), it is not consistent internally as the bytecode address is displayed only for builtins and specials and only when their formals are in .ArgsEnv
(they can also be in .GenericArgsEnv
). Now fixed in R-devel. Bug reports are best directed right into R bugzilla (R-devel mailing list works as well).
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