Decorating functions in R.
The tinsel package adds function decorators to R using a special #.
comment. Decorators are a means of transforming a function without needing to rewrite the function. They allow for easy integration of new code onto existing code. These benefits are illustrated below with an example about object classes.
Say we develop a Spaceship class. In addition to our standard Spaceship class, we also need a class for a spaceship with a hyperdrive. So we develop a SpaceshipWithHyperdrive class. Hoever, given all our spaceships we also need a mothership. So we develop a MotherSpaceship. But, what if the mothership also has a hyperdrive? In this have to add two new classes, MotherSpaceship and MotherSpaceshipWithHyperdrive. While the situation is not unmanageable adding a new class for each spaceship feature, or even for every couple of features, is less than ideal.
Instead we can create a decorator for each new spaceship feature. Let's call these decorators HyperdriveSpaceshipDecorator and MotherSpaceshipDecorator. The HyperdriveSpaceshipDecorator takes the Spaceship class, with all the Spaceship methods, and adds hyperdrive-related methods. Thus, we are saved the trouble of copying over the Spaceship methods to a new class as would have been necessary to create the SpaceshipWithHyperdrive, MotherSpaceship, and MotherSpaceshipWithHyperdrive classes.
Let's create a function if_warning
which wraps a function f
such that if f(...)
would generate a warning a default value is returned instead, otherwise f(...)
is returned.
if_warning <- function(f, default) {
function(...) {
tryCatch(
f(...),
warning = function(w) {
default
})
}
}
Now let's transform the default mean
function, so instead of generating a warning the function returns Inf
. Great!
mean_inf <- if_warning(mean, Inf)
# give it a try!
mean_inf(1:5)
mean_inf(c(1, 'two', 3))
Here is where the special comment #.
comes in. The above code can be rewritten as the following,
#. if_warning(Inf)
mean_inf <- mean
The special comment #.
is used to denote a function decorator. In this example, #. if_warning
denotes if_warning
as the decorator of the decoratee mean
. mean
is passed as the first argument to if_warning
and Inf
as the second argument. The result of transforming mean
with if_warning
is assigned to mean_inf
.
In order to see the decorator annotation example in action, save the above code in a file, source the file using source_decoratees
, and then call mean_inf
once more. (Gentle reminder, the output is expected to be the same)
You can install this package using devtools.
# install.packages('devtools')
devtools::install_github('nteetor/tinsel')
Check out the source_decoratees
function to get started.
If you are working in RStudio the tinsel package includes an addin for the core function source_decoratees
. To bind the addin to a keyboard shortcut in RStudio navigate to Tools > Addins > Browse Addins > Keyboard Shorcuts. For more information about the keyboard shortcuts checkout the RStudio support page. If you choose to setup a keyboard shortcut for the addin I recommend Alt+Shift+S since Cmd+Shift+S (or Ctrl+Shift+S on Linux and Windows) is the source active file shortcut. The end result is you can quickly load your decorated functions like you would source all functions from the active file.
Cheers, Nate.