Home > R > Which functions in R base call internal code?

Which functions in R base call internal code?

In a recent question on Stack Overflow about speeding up group-by operations, Marek wondered which functions called .Internal code (and consequently were fast). I was surprised to see that there appears to be no built-in way to check whether or not this is the case (though is.primitive is available for primitive functions).

Writing such a function is quite straight forward. We simply examine the contents of the function body, and search for the string “.Internal” within it.

callsInternalCode <- function(fn)
{
+++if(!require(stringr)) stop("stringr package required")
+++any(str_detect(capture.output(body(fn)), "\\.Internal"))
}

You can retrieve all the functions in the base package with this one-liner taken from an example on the Filter help page.

funs <- Filter(is.function, sapply(ls(baseenv()), get, baseenv()))

Now getting the list of functions that call internal code is easy.

names(funs)[sapply(funs, callsInternalCode)]
[1] "abbreviate" "agrep"
[3] "all.names" "all.vars"
[5] "anyDuplicated.default" "aperm"
...

EDIT: Tweaked the regex (the ‘.’ should have been escaped.)

About these ads
Tags: ,
  1. 14th September, 2010 at 20:28 pm | #1

    Nice function, thanks for sharing it!

    I wonder how this might reflect on the issue recently raised with optimizing R (I just asked about it here: http://stackoverflow.com/questions/3706990/is-r-that-bad-that-it-should-be-rewritten-from-scratch)

    Running this code and some games on it shows we have 28% of the functions using internals and 17% of the functions using “for” loop.
    I do wonder what this means in terms of chances for improvement…

    Here’s the code I used:

    callsInternalCode <- function(fn)
    {
     if(!require(stringr)) stop("stringr package required")
     any(str_detect(capture.output(body(fn)), ".Internal"))
    }
    callsfor <- function(fn)
    {
     if(!require(stringr)) stop("stringr package required")
     any(str_detect(capture.output(body(fn)), "for"))
    }
    
     
    funs <- Filter(is.function, sapply(ls(baseenv()), get, baseenv()))
     
    #names(funs)[sapply(funs, callsInternalCode)]
    
    length(names(funs)[sapply(funs, callsInternalCode)]) / length(funs)
    length(names(funs)[sapply(funs, callsfor )]) / length(funs)
    
    
  2. Marek
    15th September, 2010 at 12:04 pm | #2

    I like it very match.
    Don’t forget about other ways to call internal functions: `.Primitive`, `.C`, `.Fortran`, `.External`, `.Call`.

  3. 15th September, 2010 at 12:23 pm | #3

    Glad you like the function. For the record, under R2.11.1 I find 1140 functions in the base environment, of which
    323 call .Internal
    178 call .Primitive
    30 call .Call
    11 call .Fortran
    7 call .C
    0 call .External (this is the equivalent of .Internal for non-R-core developers)

  1. 15th September, 2010 at 22:21 pm | #1

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 160 other followers

%d bloggers like this: