An Opinionated Tale of Why You Should Replace `<-` with `=`

Intro

Oh, where to begin? I’m a bit of an outspoken critic of the <- assignment operator. I’ve been a bit vocal about it within my department to the point where I received the following acknowledgement:

This book came to exist after James noticed me writing a bunch of RMarkdown files as notes, and told me there was a better way, bookdown. You can also blame him for the use of = as the assignment operator.

— David Dalpiaz in the README file for Applied Statistics Textbook

And I’ve been known to lovingly question the rationale behind using <- while contributing to projects in the R community:

https://github.com/RcppCore/rcpp-gallery/pull/88#issuecomment-225050328

A tale of <- and =

Within R there are 5 different assignment operators: <-, <<-, =, ->, and ->>. Though, at one point, there was a sixth assignment operator, the underscore _, but that was deprecated in R 1.9.0. The remaining assignment operators have some important differences. In particular, the <<- and ->> operators lead to a dark side of assignment to the global environment that will not be covered in this short dispatch. Meanwhile, the main assignment operators given by <-, ->, and = are all quite similar in that they perform an assignment operation.

With this being said, the = assignment operator came along sufficiently later in the life cycle of R with an appearance first in R 1.4. The official R 1.4.0 news entry in NEWS.1 is given as:

The operator “=” is now allowed as an assignment operator in the grammar, for consistency with other languages, including recent versions of S-PLUS. Assignments with “=” are basically allowed only at top-level and in braced or parenthesized expressions, to make famous errors such as “if(x=0) 1 else 2” illegal in the grammar. (There is a plan to gradually eliminate the underscore as an assignment in future versions of R.)

The bold section was added to emphasize a pre-existing behavior of R that the = assignment wasn’t able to have: assignment in parentheses. In particular, the affect of <- and -> operators change depending on where they are called when compared to =. Thus, they are said to have a greater precedence than = operator. In particular, the change that occurs regarding the <- is in part a scope violation summarized aptly as:

The effect of foo(x <- y) if the argument is evaluated is to change the value of x in the calling environment and not in the evaluation environment of foo.

The R Language Definition: Argument evaluation

That is to say, instead of assigning a temporary value to pass to the function, the <- operator overrides the calling location variable with a new assignment value and then allows the function to be evaluated on the new value.

Take for example the following empty R session and the mean function that has parameter x to receive data:

# Assignment with = 
mean(x = 1:5)
## [1] 3

x
## Error: object 'x' not found

# Assignment with <-
mean(x <- 1:5)
## [1] 3

x
## [1]  1  2  3  4  5

# Remove x from the environment to allow
# subsequent runs to obtain the first
# error.
rm(x)

Note: If you subsequently run this example, make sure to remove x from your environment!

So, we have the violation of scope that gets brought up. But, you may say like many of the folks I’ve discussed this with:

Why are you using <- for assignment in a function parameter? Clearly that is the reason for why = was introduced!

To which I respond:

There should not be a need to differentiate between assignment operators in a programming language.

But, if scope violation isn’t your cup of tea, let’s construct three scenarios that strikes at the heart of every programmer: readability. In each scenario, we will present the <- operator along side the = operator.

# Appropriate assignment
a <- 42

a = 42

# Accidently writing less than
a < -2

a = 2

# Readability diminishes... Is that -1?
a<-1

a=1

In the end, the readibility of = wins.

However, the final argument I have against the de facto use of <- is the fact that it is four characters (2 spaces, 1 less than, and 1 minus sign) compared to three characters (2 spaces and equal sign).

Opposing Views

I realize that I may be in the minority on this topic. However, its important to recognize that largely there have been no discussions as to why <- is prefered outside of…

Darn kids, get off my lawn… Back in my day we would use <- on our keyboard.

Photo by Karl Broman from UseR 2016

Or Google’s Style Guide that simply states:

Use <-, not =, for assignment.

GOOD:

x <- 5

BAD:

x = 5

This style was also copied verbatim by Hadley Wickham in Advanced R without further explanation. In his most recent book, R for Data Science, he takes a more stronger view point and calls = users lazy without providing much of an explanation.

You will make lots of assignments and <- is a pain to type. Don’t be lazy and use =: it will work, but it will cause confusion later. Instead, use RStudio’s keyboard shortcut: Alt + - (the minus sign).

— Hadley Wickham in R for Data Science: Coding Basics

Elsewhere, R Inferno provides a more grounded approach when compared to the prior discussion in Chimera 8.2.26 with the caveat that:

Standard advice is to avoid using = when you mean <- even though it takes an extra keystroke. However, it is largely a matter of taste (as long as you know the differences).

— Patrick Burns in R Inferno

Fin

In short, assignment now is about style and preference. There is no need to push assignment using <- since modern keyboards lack the <- key while possessing =. Furthermore, by using the common assignment convention throughout programming, the transference of skills from learning R to other programming languages decreases.