Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assigning a locked variable in an R package

I'm trying to assign Pascal-Case versions of the variables true, false, na and null into my R package. This is very easy to do, but I also want to lock the binding to prevent renaming of the variable.

# An anti-example from the base libraries
F <- TRUE
T <- FALSE

T && T
FALSE

I can't figure out how to lock a variable in a package to prevent further modification. The follow mock package doesn't work

# test.R
True <- TRUE
lockBinding('True', environment())

#DESCRIPTION
Collate:
    'test.R'

When running R CMD check I get the following error:

Error in eval(expr, envir, enclos) : 
    cannot change value of locked binding for 'True'

What is the correct way of locking an R package variable so it can't be re-assigned?

edit: included the wrong error message.

like image 728
Róisín Grannell Avatar asked Jan 18 '14 20:01

Róisín Grannell


1 Answers

Mostly not answering your question. I agree with @IShouldByABoat that there's more going on, a package with the simple structure you indicate doesn't generate the error you see for me. Likely you're trying to modify True elsewhere in your code (!) or perhaps you've got some cruft in your .Rprofile or .RData file that is interfering -- run your check as R --vanilla CMD check.

Functions and symbols are defined in a package name space, for instance

library(plyr)             ## load package name space, attach to the search() path
getNamespace(plyr)        ## package name space
ls(getNamespace(plyr))    ## symbols defined in the name space
plyr::llply               ## definition of `llply` in the name space

The package name space is locked after it has been loaded

assign("llply", identity, envir=getNamespace("plyr"))
## Error in assign("llply", identity, envir = getNamespace("plyr")) : 
##   cannot change value of locked binding for 'llply'

Assigning to a similarly named variable at the command line creates a new variable in the .GlobalEnv (the first location on the search() path) rather than modifying the variable in the package name space

ls()               ## no symbol 'llply' in .GlobalEnv
llply <- identity  ## new symbol 'llply' in .GlobalEnv
llply(10)          ## use first llply function in search(), i.e., in .GlobalEnv
plyr::llply(10)    ## circumvent search path and use llply from plyr name space

So code such as

True <- TRUE
lockBinding("True", environment())

only adds a locked binding from the time True is created until the package is loaded; after that the binding is locked anyway.

Maybe you want to create a variable True in the user's .GlobalEnv, and make that so that it cannot be changed. This has to be done when the package is load'ed (or attach'ed), when the user's current .GlobalEnv is visible, with something like

.onAttach <- function(...) {
    assign("True", TRUE, .GlobalEnv)
    lockBinding("True", .GlobalEnv)
}

This only locks the binding in the .GlobalEnv so it cannot be changed, but does not stop the user from removing it (e.g., using rm("True")). Messing with your user's .GlobalEnv will likely also serve to irritate your user more than further your programming agenda.

like image 176
Martin Morgan Avatar answered Nov 10 '22 09:11

Martin Morgan