What, No Parentheses?

I’m about to show you an R trick. Various readers may find it cool, useful and interesting, or stupid, useless and an evil deed undermining the sanctity of R’s functional programming nature (“All bow”). But I hope many of you will find the material here rather intriguing if not useful.

All this involves a trick one can employ while working in R’s top level from interactive mode, the familiar > prompt.

I’ll use as an toy example here. Let’s say I have some counting variable x that I need to increment occasionally as I work. Of course, the straightforward way to do this is

x <- x + 1

But to save typing and reduce distraction from my main thought processes, it would be nice if I were able to simply type

ix

Of course, the straightforward way to do this would be to define a function ix() (“increment x”),

ix <- function() x <<- x + 1

and then call it each time by typing

ix()

But again, I want to save typing, and don’t want to type the parentheses. How can I arrange this?

My approach here will be to exploit the fact that in R’s interactive mode, typing an expression will print the value of that expression. If I type, say

y

R will first determine the class of y, and invoke the print method for that class. If I write that method myself, I can put any R code in there that I wish, such as code to increment x above! So here goes:

> w <- list(y=3)
> class(w) <- 'ix'
> print.ix <- function(ixObject) x <<- x + 1
> x <- 88
> w
> x
[1] 89
> w
> x
[1] 90

I set up an S3 class ‘ix’, including a print method print.ix(). I created w, an instance of that class, and as you can see, each time I typed ‘w’, x did get incremented by 1.

What just happened? When I type ‘w’, the R interpreter will know that I want to print that variable. The interpreter finds that w is of class ‘ix’, so it calls the print method for that class, print.ix(), which actually doesn’t do any printing; it merely increments x, as desired.

So I don’t even need to type out even the 4 characters ‘ix()’, or even the 2 characters ‘ix’; just typing the single character ‘w’ suffices. A small thing, maybe, but very useful to me when, in the frenzy of code development and especially debugging, I am able to keep distractions from my train of thought to a minimum.

By the way, we have been doing further development on our polyreg package, with some interesting new features. More news on that soon.

9 thoughts on “What, No Parentheses?”

  1. This doesn’t work within functions (or blocks), but there is a way to enable that functionality using “active bindings”:


    makeActiveBinding("x",
    local({.x <- 0; function(z) if (missing(z)) (.x <<- .x + 1) else (.x <<- z)}),
    env=.GlobalEnv)
    x
    # [1] 1
    x
    # [1] 2
    { x; cat('hello\n'); x; cat('bye\n'); }
    # hello
    # bye
    x
    # [1] 5
    x <- 11
    x
    # [1] 12

    To store the next value (not-incrementing), just assign it:


    a <- x
    a
    # [1] 13
    x
    # [1] 14
    x
    # [1] 15
    a
    # [1] 13

    1. You can get just what the original post asked for with

      makeActiveBinding (“ix”, function() x<<-x+1, .GlobalEnv)

      1. Not quite … the function given to `makeActiveBinding` needs to at least accept an argument, even if it does not differentiate between the “getter” (no argument provided) and the “setter” (one argument provided) modes of the function.
        From a stylistic perspective, the requirement to use two different variables does not seem to add much/any value here: the OP’s use of “w” and “x” avoids circular references (during the S3 approach), but that is not required with the active bindings.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.