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)
tinsel is now available on CRAN.
install.packages('tinsel')
You can install the latest version of tinsel using devtools (currently even with version 0.0.1 on CRAN).
# 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.