Easy Ruby: Plus-Equals (+=) vs. Shovel (<<)

The difference between plus-equals (+=) and shovel (<<) is a common source of confusion and frustration when first working with strings in Ruby.

If we say…

santa = 'Saint'
claus = santa
santa += ' Nick'

…then santa will yield the string Saint Nick, while claus will yield the string Saint.

Makes sense, right? Changing santa doesn’t affect claus.

Now let’s ruin Christmas!

Confusion at the North Pole

If we say…

santa = 'Saint'
claus = santa
santa << ' Nick'

…then santa will yield the string Saint Nick, while claus will also yield the string Saint Nick.

WTF, Santa?!

Explanation

To understand how += and << affect strings, we need three simple mental models:

  • Variables point to objects
  • The assignment operator (=) affects variables
  • The append operator (<<) affects objects

In Ruby, a variable is initialized the first time an object is assigned to it:

santa = 'Saint'

The code above says, “Computer, we need you to store an object for us — the string ‘Saint’. We may need to use this object later, or even change it! Things could get crazy! But, no matter how it changes, we need to make sure we’re always talking about the same object. So, let’s have a codeword for the address in memory where ‘Saint’ is stored. Let’s use the codeword santa. Go team!”

So, if we say…

santa = 'Saint'
santa = 'Saint Nick'

…we aren’t changing the Saint object by adding Nick to it. We’re storing a different object at (most likely) a different place in memory, and re-pointing the santa variable to this other memory address.

We aren’t changing the object, even if we concatenate and re-assign. It’s still just an assignment of a variable:

santa = 'Saint'
santa = santa + ' Nick'

The same is true even if we use some fancy syntactic sugar (or, in Santa’s case, syntactic sugarplums) to concatenate and re-assign:

santa = 'Saint'
santa += ' Nick'

The plus-equals operator (+=) doesn’t change objects. It changes what variables point to, via concatenation and assignment.

But, what if we want the opposite —to keep the variable pointing to the same spot in memory, and yet change the string located there?

(Hint: the append operator (<<) is about to come through in the clutch and save Christmas!)

santa = 'Saint'
santa << ' Nick'

Here we are saying “Computer, please create a string object ‘Saint’, store it at some address, and we’ll talk about that address later using the codeword santa.” Then, using the <<, we are saying, “Computer, remember that object you’re saving for us at the santa address? Please add ‘ Nick’ to the end of that object. Thanks, computer!”

The object changes, while the variable does not. The variable continues to point to the same address in memory.

To bring us full circle to our original, confusing example, if we say…

santa = 'Saint'
claus = santa
santa << ' Nick'

…we will have…

  • santa yielding Saint Nick, and
  • claus also yielding Saint Nick!

This is because the << operator affects objects, while += affects variables. We pointed santa to a string object, and then pointed claus to santa—i.e., to the same address in memory.

A note for Ruby Newbies

Technically << and += are not operators. << and + are methods (in Ruby, santa << ' Nick' is the same as santa.<<(' Nick')), while += is a shortcut combining assignment and the concatenation method. I used the term “operator” loosely but intentionally, for the sake of my fellow Ruby Newbies trying to Google answers to this issue.


This post first appeared on Medium. It was edited for clarity on 2018.12.18.

Share to: