In object-oriented R programming (especially Winston Chang's R6 package), what is an active binding?
A cool feature of {R6} is active binding , which is the process of using a symbol which looks like a variable but behave as a function. You can create these with the active method when defining your class.
R includes two different mechanisms for object-oriented programming. As you may recall, the R language is derived from the S language. S's object-oriented programming system evolved over time. Around 1990, S version 3 (S3) introduced class attributes that allowed single-argument methods.
Unlike most other programming languages, R has a three-class system. These are S3, S4, and Reference Classes.
First it is probably best to understand what a "binding" is. If we run code like:
x <- 5
then what has happened inside the computer is that we have put the value of 5 into a slot of memory and we have also 'bound' the name "x" to that location and value so that later we can use x
and it will go to that memory location and look up the value (which is 5 until we change it to something else). This is called a static binding because the value does not change unless the program specifically makes a change.
An active binding is similar in that we bind a variable name (like "x") to something, but that something is not just a constant value, but rather a function that will be run every time we try to access x
. So you could bind the name "x" to a function that calls rnorm
and then each time you access x
you would see a different random normal value.
Another example, consider if we do something with static bindings like:
mydf <- data.frame( x=1:10, y=10:1 )
df.size <- nrow(mydf)
mydf <- data.frame(z=1:100)
Now the variable df.size
has the number of rows of mydf
when it was created, not how many rows it has now (since nrow
was run once, then the result was put into the df.size
variable as a static binding, it does not update with changes to the data frame). If on the other hand we created an active binding between df.size
and a function that ran nrow(mydf)
then any time we looked at the "value" of df.size
then it would show the current number of rows in mydf
no matter how many times we change it.
1) R In R, the idea of an active binding is that you can define something that looks like a variable but it actually invokes a function each time it is accessed.
For example, after the makeActiveBinding
statement below each time randomNo
is used as a variable it calls the function specified in the second argument to makeActiveBinding
(which in this case generates a normal random variate) and returns the function's value:
makeActiveBinding("randomNo", function() rnorm(1), .GlobalEnv)
set.seed(123) # for reproducibility
randomNo
## [1] -0.5604756
randomNo
## [1] -0.2301775
2) R6 Similarly, in R6 an active binding looks like a field but it actually runs a function when accessed returning the value of the function.
Here is the example in (1) redone with R6 active bindings. Note that each time the field randomNo
is accessed the associated function (which generates a normal random variate) is invoked and its value returned as the value of the field.
library(R6)
RandomClass <- R6Class("Numbers",
active = list(
randomNo = function() rnorm(1)
)
)
set.seed(123)
randomObject <- RandomClass$new()
randomObject$randomNo
## [1] -0.5604756
randomObject$randomNo
## [1] -0.2301775
3) R6 - second example Another example can be found in the R6 active binding documentation here. In that example, each time the field x2
is accessed as if it were an ordinary field, there is a call made to the function associated with x2
(without passing any arguments to it) and the value of x2
is the result of running that function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With