How can I view the source code for a function?
Asked Answered
P

13

695

I want to look at the source code for a function to see how it works. I know I can print a function by typing its name at the prompt:

> t
function (x) 
UseMethod("t")
<bytecode: 0x2332948>
<environment: namespace:base>

In this case, what does UseMethod("t") mean? How do I find the source code that's actually being used by, for example: t(1:10)?

Is there a difference between when I see UseMethod and when I see standardGeneric and showMethods, as with with?

> with
standardGeneric for "with" defined from package "base"

function (data, expr, ...) 
standardGeneric("with")
<bytecode: 0x102fb3fc0>
<environment: 0x102fab988>
Methods may be defined for arguments: data
Use  showMethods("with")  for currently available ones.

In other cases, I can see that R functions are being called, but I can't find the source code for those functions.

> ts.union
function (..., dframe = FALSE) 
.cbind.ts(list(...), .makeNamesTs(...), dframe = dframe, union = TRUE)
<bytecode: 0x36fbf88>
<environment: namespace:stats>
> .cbindts
Error: object '.cbindts' not found
> .makeNamesTs
Error: object '.makeNamesTs' not found

How do I find functions like .cbindts and .makeNamesTs?

In still other cases, there's a bit of R code, but most of work seems to be done somewhere else.

> matrix
function (data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL) 
{
    if (is.object(data) || !is.atomic(data)) 
        data <- as.vector(data)
    .Internal(matrix(data, nrow, ncol, byrow, dimnames, missing(nrow), 
        missing(ncol)))
}
<bytecode: 0x134bd10>
<environment: namespace:base>
> .Internal
function (call)  .Primitive(".Internal")
> .Primitive
function (name)  .Primitive(".Primitive")

How do I find out what the .Primitive function does? Similarly, some functions call .C, .Call, .Fortran, .External, or .Internal. How can I find the source code for those?

Primogeniture answered 7/10, 2013 at 13:58 Comment(3)
See also https://mcmap.net/q/64711/-how-to-examine-the-code-of-a-function-in-r-that-39-s-object-class-sensitive/134830Angelinaangeline
see also #14036006Trichloromethane
See also #9385911Dialytic
P
645

UseMethod("t") is telling you that t() is a (S3) generic function that has methods for different object classes.

The S3 method dispatch system

For S3 classes, you can use the methods function to list the methods for a particular generic function or class.

> methods(t)
[1] t.data.frame t.default    t.ts*       

   Non-visible functions are asterisked
> methods(class="ts")
 [1] aggregate.ts     as.data.frame.ts cbind.ts*        cycle.ts*       
 [5] diffinv.ts*      diff.ts          kernapply.ts*    lines.ts        
 [9] monthplot.ts*    na.omit.ts*      Ops.ts*          plot.ts         
[13] print.ts         time.ts*         [<-.ts*          [.ts*           
[17] t.ts*            window<-.ts*     window.ts*      

   Non-visible functions are asterisked

"Non-visible functions are asterisked" means the function is not exported from its package's namespace. You can still view its source code via the ::: function (i.e. stats:::t.ts), or by using getAnywhere(). getAnywhere() is useful because you don't have to know which package the function came from.

> getAnywhere(t.ts)
A single object matching ‘t.ts’ was found
It was found in the following places
  registered S3 method for t from namespace stats
  namespace:stats
with value

function (x) 
{
    cl <- oldClass(x)
    other <- !(cl %in% c("ts", "mts"))
    class(x) <- if (any(other)) 
        cl[other]
    attr(x, "tsp") <- NULL
    t(x)
}
<bytecode: 0x294e410>
<environment: namespace:stats>

The S4 method dispatch system

The S4 system is a newer method dispatch system and is an alternative to the S3 system. Here is an example of an S4 function:

> library(Matrix)
Loading required package: lattice
> chol2inv
standardGeneric for "chol2inv" defined from package "base"

function (x, ...) 
standardGeneric("chol2inv")
<bytecode: 0x000000000eafd790>
<environment: 0x000000000eb06f10>
Methods may be defined for arguments: x
Use  showMethods("chol2inv")  for currently available ones.

The output already offers a lot of information. standardGeneric is an indicator of an S4 function. The method to see defined S4 methods is offered helpfully:

> showMethods(chol2inv)
Function: chol2inv (package base)
x="ANY"
x="CHMfactor"
x="denseMatrix"
x="diagonalMatrix"
x="dtrMatrix"
x="sparseMatrix"

getMethod can be used to see the source code of one of the methods:

> getMethod("chol2inv", "diagonalMatrix")
Method Definition:

function (x, ...) 
{
    chk.s(...)
    tcrossprod(solve(x))
}
<bytecode: 0x000000000ea2cc70>
<environment: namespace:Matrix>

Signatures:
        x               
target  "diagonalMatrix"
defined "diagonalMatrix"

There are also methods with more complex signatures for each method, for example

require(raster)
showMethods(extract)
Function: extract (package raster)
x="Raster", y="data.frame"
x="Raster", y="Extent"
x="Raster", y="matrix"
x="Raster", y="SpatialLines"
x="Raster", y="SpatialPoints"
x="Raster", y="SpatialPolygons"
x="Raster", y="vector"

To see the source code for one of these methods the entire signature must be supplied, e.g.

getMethod("extract" , signature = c( x = "Raster" , y = "SpatialPolygons") )

It will not suffice to supply the partial signature

getMethod("extract",signature="SpatialPolygons")
#Error in getMethod("extract", signature = "SpatialPolygons") : 
#  No method found for function "extract" and signature SpatialPolygons

Functions that call unexported functions

In the case of ts.union, .cbindts and .makeNamesTs are unexported functions from the stats namespace. You can view the source code of unexported functions by using the ::: operator or getAnywhere.

> stats:::.makeNamesTs
function (...) 
{
    l <- as.list(substitute(list(...)))[-1L]
    nm <- names(l)
    fixup <- if (is.null(nm)) 
        seq_along(l)
    else nm == ""
    dep <- sapply(l[fixup], function(x) deparse(x)[1L])
    if (is.null(nm)) 
        return(dep)
    if (any(fixup)) 
        nm[fixup] <- dep
    nm
}
<bytecode: 0x38140d0>
<environment: namespace:stats>

Functions that call compiled code

Note that "compiled" does not refer to byte-compiled R code as created by the compiler package. The <bytecode: 0x294e410> line in the above output indicates that the function is byte-compiled, and you can still view the source from the R command line.

Functions that call .C, .Call, .Fortran, .External, .Internal, or .Primitive are calling entry points in compiled code, so you will have to look at sources of the compiled code if you want to fully understand the function. This GitHub mirror of the R source code is a decent place to start. The function pryr::show_c_source can be a useful tool as it will take you directly to a GitHub page for .Internal and .Primitive calls. Packages may use .C, .Call, .Fortran, and .External; but not .Internal or .Primitive, because these are used to call functions built into the R interpreter.

Calls to some of the above functions may use an object instead of a character string to reference the compiled function. In those cases, the object is of class "NativeSymbolInfo", "RegisteredNativeSymbol", or "NativeSymbol"; and printing the object yields useful information. For example, optim calls .External2(C_optimhess, res$par, fn1, gr1, con) (note that's C_optimhess, not "C_optimhess"). optim is in the stats package, so you can type stats:::C_optimhess to see information about the compiled function being called.

Compiled code in a package

If you want to view compiled code in a package, you will need to download/unpack the package source. The installed binaries are not sufficient. A package's source code is available from the same CRAN (or CRAN compatible) repository that the package was originally installed from. The download.packages() function can get the package source for you.

download.packages(pkgs = "Matrix", 
                  destdir = ".",
                  type = "source")

This will download the source version of the Matrix package and save the corresponding .tar.gz file in the current directory. Source code for compiled functions can be found in the src directory of the uncompressed and untared file. The uncompressing and untaring step can be done outside of R, or from within R using the untar() function. It is possible to combine the download and expansion step into a single call (note that only one package at a time can be downloaded and unpacked in this way):

untar(download.packages(pkgs = "Matrix",
                        destdir = ".",
                        type = "source")[,2])

Alternatively, if the package development is hosted publicly (e.g. via GitHub, R-Forge, or RForge.net), you can probably browse the source code online.

Compiled code in a base package

Certain packages are considered "base" packages. These packages ship with R and their version is locked to the version of R. Examples include base, compiler, stats, and utils. As such, they are not available as separate downloadable packages on CRAN as described above. Rather, they are part of the R source tree in individual package directories under /src/library/. How to access the R source is described in the next section.

Compiled code built into the R interpreter

If you want to view the code built-in to the R interpreter, you will need to download/unpack the R sources; or you can view the sources online via the R Subversion repository or Winston Chang's github mirror.

Uwe Ligges's R news article (PDF) (p. 43) is a good general reference of how to view the source code for .Internal and .Primitive functions. The basic steps are to first look for the function name in src/main/names.c and then search for the "C-entry" name in the files in src/main/*.

Primogeniture answered 7/10, 2013 at 13:58 Comment(10)
If you use RStudio, it will attempt to pull the source for the function your text cursor is over if you press the F2 key.Extinguisher
@Ari B. Friedman Sorry for this late question. Will RStudio also pull the C source code for the function or just for the functions written in R? ThanksIntestinal
@Samir I believe it's just the R source.Extinguisher
@AriB.Friedman - thanks Ari, this is handy. In my case I still needed the knowledge shown in the answer (scale, which is S3 - I got UseMethod("scale") and then used getAnywhere(scale.default)). But plain functions work just fine.Pazit
Imitation is the sincerest form of flattery I assume this answer / wiki came first :) Before this rfaqs.com/source-code-of-r-methodExcitable
How can we find the compiled code in this github folder? I want to find the source code for function stl and it calls a Fortran function z <- .Fortran(C_stl, x, n, as.integer(period).... But I can't find C_stl in that folder. Would it be somewhere else?Yelmene
@yuqli: Note that it's C_stl, not "C_stl". Use print(stats:::C_stl) to see the NativeSymbolInfo for the C_stl object. That shows that the Fortran function name is "stl", which is in the stl.f file.Primogeniture
@JoshuaUlrich Thanks for the response! I later searched "stl" and did also find the stl.f file. But thanks so much for teaching me the trick of printing and the difference between an object and a file.Yelmene
Alas getMethod() is deprecated and not longer available. The help file for findMethods() which replaced it does not show how to get the source code for S4 methods.Nedrud
I'm using R version 4.1.3 and getMethod() works just fine for me i.e. gives the same output as in this post.Faye
O
114

In addition to the other answers on this question and its duplicates, here's a good way to get source code for a package function without needing to know which package it's in. e.g. say if we want the source for randomForest::rfcv():

To view/edit it in a pop-up window:

edit(getAnywhere('rfcv'), file='source_rfcv.r')

View(getAnywhere('rfcv'), file='source_rfcv.r')

Note that edit() opens a text editor (of user's choice), whereas View() invokes a spreadsheet-style data viewer.

  • View() is great for browsing (multi-columnar) data, but usually terrible for code of anything other than toy length.
  • so when only want to view code, edit() is IMO actually far better than View(), since with edit() you can collapse/hide/dummy out all the arg-parsing/checking/default/error-message logic which can take up to 70% of an R function, and just get to the part where the function actually operationally does something(!), what type(s) of objects its return type is, whether and how it recurses, etc.

To redirect to a separate file (so you can bring up the code in your favorite IDE/editor/process it with grep/etc.):

capture.output(getAnywhere('rfcv'), file='source_rfcv.r')
Oversee answered 22/5, 2014 at 22:46 Comment(4)
Admittedly, getAnywhere is another wacky R choice of name for something which should have been called findOnSearchPath or similar.Oversee
I'll upvote this answer because it got me close to what I wanted. What I actually wanted, in RStudio, was View(foo); where foo was a function from an already loaded package.Elagabalus
@Sigfried: edit() opens a text editor (of user's choice), whereas View() opens an Excel-type spreadsheet viewer for data, the latter is good for browsing (multi-columnar) data, but usually terrible for code of anything other than toy length. For example as I hint at, generally the first thing I want to do when browsing a function is skip/collapse/dummy out all the arg-parsing and default-action logic, to see what the function actually does.Oversee
@Sigfried: updated to incorporate all those remarks/tips.Oversee
G
35

For non-primitive functions, R base includes a function called body() that returns the body of function. For instance the source of the print.Date() function can be viewed:

body(print.Date)

will produce this:

{
    if (is.null(max)) 
        max <- getOption("max.print", 9999L)
    if (max < length(x)) {
        print(format(x[seq_len(max)]), max = max, ...)
        cat(" [ reached getOption(\"max.print\") -- omitted", 
            length(x) - max, "entries ]\n")
    }
    else print(format(x), max = max, ...)
    invisible(x)
}

If you are working in a script and want the function code as a character vector, you can get it.

capture.output(print(body(print.Date)))

will get you:

[1] "{"                                                                   
[2] "    if (is.null(max)) "                                              
[3] "        max <- getOption(\"max.print\", 9999L)"                      
[4] "    if (max < length(x)) {"                                          
[5] "        print(format(x[seq_len(max)]), max = max, ...)"              
[6] "        cat(\" [ reached getOption(\\\"max.print\\\") -- omitted\", "
[7] "            length(x) - max, \"entries ]\\n\")"                      
[8] "    }"                                                               
[9] "    else print(format(x), max = max, ...)"                           
[10] "    invisible(x)"                                                    
[11] "}"     

Why would I want to do such a thing? I was creating a custom S3 object (x, where class(x) = "foo") based on a list. One of the list members (named "fun") was a function and I wanted print.foo() to display the function source code, indented. So I ended up with the following snippet in print.foo():

sourceVector = capture.output(print(body(x[["fun"]])))
cat(paste0("      ", sourceVector, "\n"))

which indents and displays the code associated with x[["fun"]].

Edit 2020-12-31

A less circuitous way to get the same character vector of source code is:

sourceVector = deparse(body(x$fun))
Ginnygino answered 30/12, 2016 at 21:41 Comment(0)
S
31

It gets revealed when you debug using the debug() function. Suppose you want to see the underlying code in t() transpose function. Just typing 't', doesn't reveal much.

>t 
function (x) 
UseMethod("t")
<bytecode: 0x000000003085c010>
<environment: namespace:base>

But, Using the 'debug(functionName)', it reveals the underlying code, sans the internals.

> debug(t)
> t(co2)
debugging in: t(co2)
debug: UseMethod("t")
Browse[2]> 
debugging in: t.ts(co2)
debug: {
    cl <- oldClass(x)
    other <- !(cl %in% c("ts", "mts"))
    class(x) <- if (any(other)) 
        cl[other]
    attr(x, "tsp") <- NULL
    t(x)
}
Browse[3]> 
debug: cl <- oldClass(x)
Browse[3]> 
debug: other <- !(cl %in% c("ts", "mts"))
Browse[3]> 
debug: class(x) <- if (any(other)) cl[other]
Browse[3]>  
debug: attr(x, "tsp") <- NULL
Browse[3]> 
debug: t(x)

EDIT: debugonce() accomplishes the same without having to use undebug()

Sharecropper answered 12/8, 2014 at 7:1 Comment(3)
The downsides of this method compared to the ones given in the accepted answer are that you need a working function call (all necessary parameters specified, acceptably); and that, in addition to the initial block of code, you also get each block at the time it is run. This is great for debugging, but not optimal for just getting the source.Warden
Yes, its not optimal. But if you are clever, you can get the source quick and dirty, esp for in-built functions.Sharecropper
I'd also recommend using debugonce instead of debug in this instance.Primogeniture
D
22

Didn't see how this fit into the flow of the main answer but it stumped me for a while so I'm adding it here:

Infix Operators

To see the source code of some base infix operators (e.g., %%, %*%, %in%), use getAnywhere, e.g.:

getAnywhere("%%")
# A single object matching ‘%%’ was found
# It was found in the following places
#   package:base
#   namespace:base
#  with value
#
# function (e1, e2)  .Primitive("%%")

The main answer covers how to then use mirrors to dig deeper.

Derril answered 1/12, 2015 at 20:18 Comment(2)
smci's answer recommended getAnywhere. Or you could just use backticks if you already know the name of the operator: `%in%`.Primogeniture
@JoshuaUlrich didn't know you could use backticks! Thanks. getAnywhere is mentioned in your answer as well, but I think a specific reference to infix is useful for future reference to this answer -- I've read this page many a time and was still a bit perplexed trying to find code for such functions for a while -- and I didn't think it fit into the flow of either other answer (which are both using getAnywhere for another purpose).Derril
T
15

In RStudio, there are (at least) 3 ways:

  1. Press the F2 key while cursor is on any function.
  2. Click on the function name while holding Ctrl or Command
  3. View(function_name) (as stated above)

A new pane will open with the source code. If you reach .Primitive or .C you'll need another method, sorry.

Tremor answered 22/2, 2019 at 14:54 Comment(0)
B
14

There is a very handy function in R edit

new_optim <- edit(optim)

It will open the source code of optim using the editor specified in R's options, and then you can edit it and assign the modified function to new_optim. I like this function very much to view code or to debug the code, e.g, print some messages or variables or even assign them to a global variables for further investigation (of course you can use debug).

If you just want to view the source code and don't want the annoying long source code printed on your console, you can use

invisible(edit(optim))

Clearly, this cannot be used to view C/C++ or Fortran source code.

BTW, edit can open other objects like list, matrix, etc, which then shows the data structure with attributes as well. Function de can be used to open an excel like editor (if GUI supports it) to modify matrix or data frame and return the new one. This is handy sometimes, but should be avoided in usual case, especially when you matrix is big.

Bywaters answered 4/12, 2014 at 23:39 Comment(3)
This approach only brings up the same function source that printing the function gives (that is, the same as in the question). Getting further/deeper than that is what this question is about.Warden
@BrianDiggs Yes, you are right. I did not mean to give an answer to the question, since Joshua has given a quite complete answer. I just try to add something related to the topic, interesting and may be useful to know about.Bywaters
Excuse me, I had posted this 7 months earlier. The use of invisible(edit(...)) is a good tip though, also the remark "doesn't work on C/C++ or Fortran".Oversee
P
9

As long as the function is written in pure R not C/C++/Fortran, one may use the following. Otherwise the best way is debugging and using "jump into":

> functionBody(functionName)
Photogenic answered 24/1, 2017 at 16:42 Comment(2)
This is the same as body. identical(functionBody, body) is TRUE.Primogeniture
base::body and methods::functionBody, though they're unlikey to be detahed. body could be overridden too: rdocumentation.org/search?q=bodyNightspot
T
6

View(function_name) - eg. View(mean) Make sure to use uppercase [V]. The read-only code will open in the editor.

Tridentine answered 11/1, 2017 at 2:45 Comment(1)
?View requires a data frame like object, it does not accept a function (in base R). What you are describing is an RStudio modification.Crick
R
5

You can also try to use print.function(), which is S3 generic, to get the function write in the console.

Redbug answered 26/12, 2017 at 11:45 Comment(1)
print.function() is a S3 method. The generic is print(). And it's generally not a good idea to call methods directly. That defeats the entire purpose of generic functions and method dispatch.Primogeniture
P
2

To see the source code of the function use print()

f <- function(x){
     x * 2
 }

print(f)

function(x){
    x * 2
}
Proficient answered 10/8, 2021 at 7:48 Comment(0)
E
1

First, try running the function without ()

Example: let's get the source code for the cat() function:

cat
    if (is.character(file)) 
        if (file == "") 
            file <- stdout()
        else if (startsWith(file, "|")) {
            file <- pipe(substring(file, 2L), "w")
            on.exit(close(file))
        }
        else {
            file <- file(file, ifelse(append, "a", "w"))
            on.exit(close(file))
        }
    .Internal(cat(list(...), file, sep, fill, labels, append))

But sometimes that will return "UseMethod" instead of source code

If we try to get the source code for read_xml():

library(xml2)
read_xml 
# UseMethod("read_xml")

That's not much use to us! In this case, take a look at the methods:

methods("read_xml")
# read_xml.character* read_xml.connection* read_xml.raw* read_xml.response* 

And use getAnywhere on the value(s) above to see the source code:

getAnywhere("read_xml.character")

Another example

Let's try to see the source code for qqnorm():

qqnorm
# UseMethod("qqnorm") # Not very useful

methods("qqnorm")
# [1] qqnorm.default* # Making progress...

getAnywhere("qqnorm.default") # Shows source code!
Elective answered 20/5, 2022 at 13:16 Comment(4)
Did you read the answer by @JoshuaUlrich?Collimate
@JosephWood I did, it was where I got these techniques from a few years ago. I was recently asked why the source code for qqnorm() doesn't appear when someone runs qqnorm so referred to this question/answers, but couldn't figure it out rapidly, so decided to leave my own answer giving a small handful of MRE's (albeit limited ones, not demonstrating more complicated situations, for example invoking c/c++/fortran code etc). If I've missed something, or if I'm wrong please point out and I'll amend.Elective
It has been my experience that posting an answer that doesn't add any new information is generally not received well. Especially noting that there is no disclaimer that this is essentially a condensed version of the accepted canonical answer.Collimate
@JosephWood Your points are fair. I'd hold that simple answers are sometimes nice (even nicer).. Mine's a 30 seconds read for a newbie, the top answer is much more thorough and hence takes more time, which can be intimidating for someone after a quick, practical answer. Mine is not comprehensive, nor does it try to explain why functions can require different methods to discover their source, instead, it gives examples for how to get the source code for a function, without needing to know too much about R's dispatch system, so it's reductionist and simpler, albeit nowhere near as thorough.Elective
S
0

A quick solution for the R-plugin in PyCharm (for RStudio, see the answer by @Arthur Yip). Type, if necessary, and select the function name in the Editor or R Console. Then "Go to Declaration" or use shortcuts CTRL-B or Command-B. Note: this is not useful for .Primitive (ie, internally implemented) functions.

Sciolism answered 24/7, 2022 at 20:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.