Jim Green
Jim Green

Reputation: 271

.First function in R

I don't understand the point of .First function in R. My reason is any code in .Rprofile will be sourced and executed when R starts up anyway.

this

.First<-function(){                                                                 
    library('devtools')                                     
}

and this

library('devtools')

in .Rprofile have exactly the same effect.

However, here is an example that shows .First can make a difference:

example 1, you can see X11.options()$type correctly becomes Xlib as set in .Rprofile

>> cat .Rprofile
.First <- function() {
    library(devtools)
}

setHook(
    packageEvent("grDevices", "onLoad"),
    function(...) grDevices::X11.options(type="Xlib")
)

>> Rscript -e 'X11.options()$type'
[1] "Xlib"

example 2, you can see X11.options()$type is still cairo, the setHook in .Rprofile didn't take effect

>> cat .Rprofile
library(devtools)

setHook(
    packageEvent("grDevices", "onLoad"),
    function(...) grDevices::X11.options(type="Xlib")
)

>> Rscript -e 'X11.options()$type'
[1] "cairo"

Thanks!

Upvotes: 8

Views: 3278

Answers (3)

braaadwb
braaadwb

Reputation: 1

R sources Rprofile.site then either project-level or user-level .Rprofile and then evaluates .First (Rstudio Support).

.First is useful to include in Rprofile.site if you want to trigger an action (site-wide) that is conditional on user or project .Rprofile.

Example: renv is activated by project-level .Rprofile.

This code will print a message indicating the location of the renv cache or will alert the user that renv hasn't been activated.

if (interactive()) {
  .First <- function() {
    if ("RENV_PROJECT" %in% names(Sys.getenv())) {
      cat("\nLinked to renv cache:\n")
      cat("-", renv::paths$cache(), "\n\n")
    } else {
      cat("\n***  Warning:  you are not in an active renv project! ***\n")
      cat("- Some functions may be unavailable.\n\n")
    }
  }
}

Upvotes: 0

scoco
scoco

Reputation: 57

One benefit of putting startup code in .First() instead of .RProfile is that you can use local variables which won't stay in your Global environment after .First() completes.

For example, my .First() displays the list of .R files on the project directory in as many columns as will fit:

localFiles <- list.files(pattern = "\\.R$", ignore.case = TRUE)
maxChars <- max(nchar(localFiles))
numCols <- as.integer((options("width")$width-2) / (1 + maxChars))  # how many columns will fit?
fmt <- sprint(" %%-%d", maxChars)                  # left justified in each column
for (nn in localFiles) {
  if ((match(nn, localFiles) %% numCols) == 1) cat(" ")   # indent each row
  cat(sprint(fmt, nn))
  if ((match(nn, localFiles) %% numCols) == 0) cat("\n")  # end of row
}
if (length(localFiles) %% numCols != 0) cat("\n")         # end last row if not complete

Since this is in .First(), all of the temporary variables get cleaned up when the function returns and the Global environment remains clean.

Upvotes: 2

DAV
DAV

Reputation: 756

It may be unnecessary but it does provide yet another place to modify the startup. It certainly doesn't hurt having it.

I generally run R in different directories to keep things separated; link to a common .Rprofile; and use .First to tailor the current R run environment to the specific problem I'm working on. If .First action wasn't available I'd have to create one.

Upvotes: 1

Related Questions