Richie Cotton
Richie Cotton

Reputation: 121077

What does builtins(internal = TRUE) return?

From ?builtins:

builtins(TRUE) returns an unsorted list of the names of internal functions, that is those which can be accessed as .Internal(foo(args ...)) for foo in the list.

I don't understand which functions are being returned.

I thought it would be all the closure functions in the base package that call .Internal().

However, the two sets don't match up.

base_objects <- mget(
  ls(baseenv(), all.names = TRUE), 
  envir = baseenv()
)

internals <- names(
  Filter(
    assertive.types::is_internal_function,
    base_objects
  )
)
builtins_true <- builtins(internal = TRUE)
c(
  both = length(intersect(internals, builtins_true)),
  internals_not_builtins_true = length(setdiff(internals, builtins_true)),
  builtins_true_not_internals = length(setdiff(builtins_true, internals))
)
##                        both internals_not_builtins_true builtins_true_not_internals 
##                         288                         125                         226

I also thought that it might be the values listed in src/main/names.c in R's source code, and there definitely seems to be some overlap with this, but it isn't exactly this list of values.

What is builtins() doing when you pass internal = TRUE?

Upvotes: 2

Views: 83

Answers (2)

Richie Cotton
Richie Cotton

Reputation: 121077

After more digging, it seems that the list of functions is everything in the R_FunTab[] object in src/main/names.c where the second digit of the eval column is 1.

Here's a script to retrieve them.

library(stringi)
library(magrittr)
library(dplyr)

names.c <- readLines("https://raw.githubusercontent.com/wch/r-source/56a1b08b7282c5488acb71ee244098f4fd94f7c7/src/main/names.c")

fun_tab <- names.c[92:974] %>% 
  stri_replace_all_regex("^\\{", "") %>% 
  stri_replace_all_fixed("{PP", "PP") %>% 
  stri_replace_all_fixed("}},", "") %>% 
  stri_replace_all_fixed("\\t", "")
funs <- read.csv(text = fun_tab, header = FALSE, comment.char = "/")

cols <- names.c[86] %>% 
  stri_sub(4) %>% 
  stri_split_regex("\\t+") %>% 
  extract2(1) %>% 
  stri_trim()
colnames(funs) <- cols

funs$eval <- formatC(funs$eval, width = 3, flag = "0")

# Internal fns have 2nd digit of eval col == 1. See names.c[62:71]
internals <- funs %>% filter_(~ substring(eval, 2, 2) == 1)

I see slight differences when examining

setdiff(internals$printname, builtins(TRUE))
setdiff(builtins(TRUE), internals$printname)

For example builtins(TRUE) doesn't include shell.exec() if you aren't running Windows; mem.limits() was only recently removed from the devel branch of R, so it shows up in builtins(TRUE) for the current release version of R.

Upvotes: 1

Joshua Ulrich
Joshua Ulrich

Reputation: 176648

Stibu's comment is a specific example of the general problem. ?builtins says that it fetches the names of the objects it returns directly from the symbol table (this is the C symbol table).

And builtins(TRUE) returns all the built-in objects callable via .Internal. That, however, doesn't mean there must be any function that calls .Internal(foo(args, ...)) for any foo.

Stibu gave one example: the internal function may not be called by an R function with the same name, as is the case for many generic functions where the default method calls .Internal.

Another example is something like .addCondHands and .addRestart, which are called by withCallingHandlers and withRestarts, respectively.

It's also possible that one R function calls multiple .Internal functions. I don't know of an example of that off the top of my head though.

Upvotes: 2

Related Questions