DEV Community

Colin Fay
Colin Fay

Posted on • Originally published at colinfay.me on

1 2

JavaScript cont in R

One thing I like about JavaScript is the const declaration method, which allows you to declare a variable one time, and that variable can’t be reassigned after that. I.e, this piece of code will throw an error:

node -e "const x = 12; x = 14"


## [eval]:1
## const x = 12; x = 14
## ^
## 
## TypeError: Assignment to constant variable.
## at [eval]:1:18
## at Script.runInThisContext (vm.js:124:20)
## at Object.runInThisContext (vm.js:314:38)
## at Object.<anonymous> ([eval]-wrapper:9:26)
## at Module._compile (internal/modules/cjs/loader.js:805:30)
## at evalScript (internal/process/execution.js:60:25)
## at internal/main/eval_string.js:16:1

Enter fullscreen mode Exit fullscreen mode

The cool thing about this is that you can’t override the variable by mistake: once it’s set, it’s set. On the other hand, R allows you to override almost any variable (well, except some reserved variables).

I asked Twitter if there was any implementation of that concept in R.The use case, for example, would arise when you have a value that takes some time to compute. If I do my computation, I can accidentally override it later on. Event more if you’re using notebook, where you create symbols and values all along your document.

a <- some_very_complex_computation()
# [...] Going on the weekend
a <- "Hello there!"

Enter fullscreen mode Exit fullscreen mode

Here, I have no way to prevent myself from erasing the value in a. Of course, there are always rigour, explicit variable name, and not-assigning-things-without-thinking but you know how it is in the real world, and there is no Cmd + Z there.

Romain pointed out that ?lockBinding existed, and that it was what I was looking for. And that does.

Here’s how it works: it takes a character string referring to a symbol, and an environment, and prevents from assigning any new value to this symbol in the given environment.

x <- 12
lockBinding("x", .GlobalEnv)
x <- 13


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

Enter fullscreen mode Exit fullscreen mode

And here’s a small wrapper to do that:

lock <- function(x){
  lockBinding(
    deparse(
      substitute(x)), 
    env = parent.frame()
  )
}

plop <- 12
lock(plop)
plop <- 13


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


pouet <- function(){
  plop <- 14
  print(plop)
  lock(plop)
  plop <- 13
}
pouet()


## [1] 14

## Error in pouet(): cannot change value of locked binding for 'plop'

Enter fullscreen mode Exit fullscreen mode

So there I could do

a <- some_very_complex_computation()
lock(a)
# [...] Going on the weekend
a <- "Hello there!"

Enter fullscreen mode Exit fullscreen mode

And there, I have prevented myself from erasing my a variable. Ofcourse, it’s not the same as JavaScript const, as there is always away to unlock the symbol.

x <- 12


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


lock(x)
x <- 13


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


unlockBinding("x", .GlobalEnv)
x <- 13
x


## [1] 13

Enter fullscreen mode Exit fullscreen mode

But I think it’s a rather elegant solution for preventing yourself fromunwanted variable overwriting.

See also:

Some answers to the Twitter thread also suggested using R6… but that will be for another post :)

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more