Site icon R-bloggers

Control the Function Scope by the R Package Namescope

[This article was first published on ЯтомизоnoR » R, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

An attractive feature of the package is the namespace.  The R language cannot write a function that has a limited scope.  But converting the same script to a package brings a scope by the namespace.  Because every package with namespace is loaded in a separated environment, functions are protected from overwriting.

aa.R

# for package a
c <- function() 'Hello from package a!'
a <- function() paste('A+', c())
b <- a

bb.R

# for package b
c <- function() 'Hello from package b!'
b <- function() paste('B+', c())

source

First, I want to show the case of non-packaged simple scripts.

After loading aa.R, the built-in function c() of base R is lost.  Because the base is also a package, the built-in c() is still available by calling base::c().

> ls()
character(0)
> source("aa.R")
> a()
[1] "A+ Hello from package a!"
> b()
[1] "A+ Hello from package a!"
> c()
[1] "Hello from package a!"
> base::c()
NULL
> ls()
[1] "a" "b" "c"

Then what happens after loading bb.R?

The b() and c() are overwritten and completely lost.  Moreover, a() shows an unexpected string, because it depends the lost c() function defined in the aa.R.

> source("bb.R")
> a()
[1] "A+ Hello from package b!"
> b()
[1] "B+ Hello from package b!"
> c()
[1] "Hello from package b!"

library

Now, build packages aa and bb for each of aa.R and bb.R.  Two reasons for me to use this package names.

  1. the package name must have 2 characters at minimum.
  2. using the same name of function and the package is not recommended, because it conflicts the name of help document aliases.

I chose to hide the function c() using a file NAMESPACE.

# NAMESPACE for package aa
export(a, b)

# NAMESPACE for package bb
export(b)

Remove sourced scripts, and then library packages from the temporary locations.

> remove(a,b,c)
> ls()
character(0)
> library(package=aa, lib.loc='/tmp/aa.Rcheck/')
> a()
[1] "A+ Hello from package a!"
> b()
[1] "A+ Hello from package a!"
> c()
NULL
> ls()
character(0)

The base::c() is not overwritten, while the a() and b() calls the aa::c() in the package.

> library(package=bb, lib.loc='/tmp/bb.Rcheck/')
The following object(s) are masked from ‘package:aa’:
b
> a()
[1] "A+ Hello from package a!"
> b()
[1] "B+ Hello from package b!"
> c()
NULL
> aa::b()
[1] "A+ Hello from package a!"
> search()
 [1] ".GlobalEnv"        "package:bb"        "package:aa"       
 [4] "tools:RGUI"        "package:stats"     "package:graphics" 
 [7] "package:grDevices" "package:utils"     "package:datasets" 
[10] "package:methods"   "Autoloads"         "package:base"

The b() function is overwritten.  But a() works correctly.  And aa:b() can access to the b() function in the package aa.

Usually, a complicated function have many private functions to help calculations.  These helper functions should be hidden in a limited scope, because these names may conflict to the global environment.  The advantage of packaging is to control the scope with the namespace.


To leave a comment for the author, please follow the link and comment on their blog: ЯтомизоnoR » R.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.