0

I'd like to create shorter aliases for some R functions, like j=paste0. However when I add the line j=paste0 to ~/.Rprofile, it is later overridden when I use j as a variable name.

I was able to create my own package by first running package.skeleton() and then running this:

rm anRpackage/R/*
echo 'j=paste0'>anRpackage/R/test.R
echo 'export("j")'>anRpackage/NAMESPACE
rm -r anRpackage/man
R CMD install anRpackage

And then library(anRpackage);j=0;j("a",1) returns "a1". However is there some easier way to prevent the function definition from being overridden by the variable assignment?

nisetama
  • 7,764
  • 1
  • 34
  • 21
  • 1
    see `lockBindings`, https://stackoverflow.com/q/3453772/13513328 – Waldi Jul 13 '22 at 16:41
  • @Waldi `lockBinding` doesn't do what I want, because I want to be able to still use `j` as a variable name even after I've defined a function named `j`. – nisetama Jul 13 '22 at 16:48

2 Answers2

1

The code in .Rprofile will run in the global environment so that's where the variable j will be defined. But if you use j as a variable later in the global environment, it will replace that value. Variables in a given environment must have unique names. But two different environments may have the same name defined and R will use the first version it finds that will work as a function when you attempt to call the variable name as a function. So basically you need to create a separate environment. You can do what with a package as you've done. You could also use attach() to add a new environment to your search path.

attach(list(j=paste0))

This will allow for the behavior you want.

attach(list(j=paste0))
j("a",1)
# [1] "a1"
j <- 5
j("a",1)
# [1] "a1"

Normally I would discourage people from using attach() because it causes confusing change to your workspace but this would do what you want. Just be careful if anyone else will be using your code because creating aliases for built in functions and reusing those as variable names is not a common thing to see in R scripts.

You can see where it was attached by looking at the output of search(). Normally it will be attached in the second position so you can remove it with detach(2)

MrFlick
  • 195,160
  • 17
  • 277
  • 295
  • If I add `attach(list(j=paste0))` to `~/.Rprofile`, and I load `.Rprofile` and I reload `.Rprofile`, then I get a warning that `The following object is masked from list(j = paste0) (pos = 3): j`. So if I wrap my custom functions in `.Rprofile` within `attach`, then can I add `for(x in rev(which(startsWith(search(),"list"))))detach(pos=x)` before `attach` it so I don't get a warning when I reload `.Rprofile`? – nisetama Jul 13 '22 at 18:26
  • Under what scenario are you reloading the `.RProfile` file after the R session starts? That seems very unusual. But yes, you should always detach before re-attaching the same values. Masking can be troublesome if you are not careful which is why the normal recommendation is to avoid `attach`. And just avoid using the same name for functions and variables. – MrFlick Jul 13 '22 at 18:30
0

I ended up putting my custom functions to ~/.R.R and I added these lines to .Rprofile:

if("myfuns"%in%search())detach("myfuns")
source("~/.R.R",attach(NULL,name="myfuns"))

From the help page of attach:

One useful ‘trick’ is to use ‘what = NULL’ (or equivalently a
length-zero list) to create a new environment on the search path
into which objects can be assigned by assign or load or
sys.source.

...

## create an environment on the search path and populate it
sys.source("myfuns.R", envir = attach(NULL, name = "myfuns"))
nisetama
  • 7,764
  • 1
  • 34
  • 21