3 min read

(What’s up with the brackets?)

In various places, from the R help pages to books to course materials, you see R code like

(x = runif(10, 0, 10))
##  [1] 1.610466 2.662462 1.517036 1.372483 4.272460 6.402148 8.347196
##  [8] 8.775537 1.863104 8.912241

which displays the value of x. Without the brackets, it doesn’t. Harkanwal Singh, on Twitter, said “I would like to know more”. So, in case he’s not the only one, this is what’s going on.

First, when you evaluate an expression in R it will usually return a value, which will be printed.

exp(pi)
## [1] 23.14069
rnorm(2)
## [1] -0.4578773  1.2234183
cos
## function (x)  .Primitive("cos")
function(x,y) {
  lm(y~x)
} 
## function(x,y) {
##   lm(y~x)
## }

The printing doesn’t always happen, for example:

boxplot(x)

Is this because boxplot doesn’t return a value? No!

a<-boxplot(x)

a
## $stats
##          [,1]
## [1,] 1.372483
## [2,] 1.610466
## [3,] 3.467461
## [4,] 8.347196
## [5,] 8.912241
## 
## $n
## [1] 10
## 
## $conf
##           [,1]
## [1,] 0.1015223
## [2,] 6.8333997
## 
## $out
## numeric(0)
## 
## $group
## numeric(0)
## 
## $names
## [1] "1"

The value returned by boxplot is somehow invisible, but only in a temporary way. In fact, if you look near the end of the boxplot.default method, you see

if (is.null(pars$boxfill) && is.null(args$boxfill)) 
            pars$boxfill <- col
do.call("bxp", c(list(z, notch = notch, width = width, 
            varwidth = varwidth, log = log, border = border, 
            pars = pars, outline = outline, horizontal = horizontal, 
            add = add, at = at), args[namedargs]))
invisible(z)

The value is returned, and tagged as invisible. It won’t print, at least not until you do something to it.1

There are two uses of the invisibility flag that are critical to usability of R but not obvious. The first is in assignments. If you type something like

bigx <- matrix(rnorm(1e6),ncol=100)

you really don’t want bigx to automatically print. But it would, without more effort: these are perfectly good expressions that return a value.

Even worse, you don’t want

print(x)
##  [1] 1.610466 2.662462 1.517036 1.372483 4.272460 6.402148 8.347196
##  [8] 8.775537 1.863104 8.912241

to print its returned value, because its returned value is typically the value of x and that way lies infinite loops. Methods for print typically return invisible(x)2. You could also get around this by having print not return a value, but that breaks the magic variable .Last.value and, anyway, it’s not what we do.

And, finally, what’s with the parentheses? The parentheses are a function

get("(")
## .Primitive("(")

It returns its argument unchanged, and, like most functions, it doesn’t set the invisibility flag. So when you type

(x = runif(10,0,10))
##  [1] 6.9129134 0.1128086 6.3230912 0.6280404 7.9812971 5.5740664 4.9418995
##  [8] 0.8299477 2.8720316 0.1819464

the inner assignment is evaluated, the value is returned invisibly, the value is passed to the ( function, this returns the same value, but it doesn’t set the invisibility flag, and the vector prints.

My recollection is that this wasn’t ever a deliberate plan, and there was a move to get rid of it at some point long ago, which was stopped partly because the trick was being used in so many base R help pages.


  1. Note: lattice and ggplot objects are different – for them, the print method is what does the plotting

  2. even the print method for ggplot objects, which draws a plot rather than printing