Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do some primitives have byte-codes and some do not?

Tags:

r

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).

like image 240
Rich Scriven Avatar asked Sep 25 '14 03:09

Rich Scriven


2 Answers

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.

like image 182
Richie Cotton Avatar answered Nov 12 '22 23:11

Richie Cotton


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).

like image 1
Tomas Kalibera Avatar answered Nov 12 '22 22:11

Tomas Kalibera