Ruby: Shovel vs. Plus Equals

This is going to be first of what I hope to be many blog posts documenting my foray into Ruby programming. Foray might be a bad choice of word given that this is not my first attempt at learning the language. However, the approach that I am taking this time around is more active than my previous attempts so I am hopeful. Like any other endeavor, this too has a goal & a specific one at that – being able to build a foundation in Ruby in time for Lone Star Ruby Conference at the end of August.

The approach this time is to follow Mike Clark‘s advice and build tests as I delve into different features of Ruby while reading The Well Grounded Rubyist by David A. Black.

The reason I am optimistic about this approach is because I am currently working through the wonderful Ruby Koans created by EdgeCase. Ruby Koans was what introduced me to Mike Clark’s approach on learning different facets of Ruby. This is a great starting point for anyone who is new to Ruby as it introduces both the core concepts or Ruby while introducing the idea of testing. Since we are not writing code, it is not test-first-development but more of an inquiry into the ruby interpreter through test cases. The best part about Ruby Koans so far is the question that are posed that forces you to move away from the hows that the tests focus on to more of the whys. I am going to focus on one such whys on this post.

The question posed in one of the Koans was in regards to String modification. The tests were for the shovel (<<) & plus equals (+=) operators. The question was:

“Ruby programmers tend to favor the shovel operator (<<) over the plus equals operator (+=) when building up strings. Why?”

At first, I did not pay attention to this & was about to move to the next failing test. However, since I wanted to do proper justice to my learning experience, I decided to think a little bit about the the two operators in relation to the question being posed. My gut feeling told me that it probably had to do with the fact that the shovel (<<) operator modifies the actual object while the plus equals (+=) operator created a new object altogether.

Of course, I was afraid of being wrong and wanted to verify this. I was about to fire up IRB to test it out when I remembered Mike Clark’s approach to learning and thought I should write a test to see if what I was thinking was the answer was true. So, I decided to write a quick test:
require ‘test/unit’

class StringTest < Test::Unit::TestCase

  def test_plus_equals_creates_new_object
    original_string = "Hello, "
    hi = original_string
    assert_equal original_string.object_id, hi.object_id
    there = "World"
    hi += there
    assert_not_equal original_string.object_id, hi.object_id
  end

  def test_shovel_does_not_create_new_object
    original_string = "Hello, "
    hi = original_string
    assert_equal original_string.object_id, hi.object_id
    there = "World"
    hi << there
    assert_equal original_string.object_id, hi.object_id
  end
end

The test proved my initial hunch. I was going to leave it at that but then I remembered that Array also use both operators. So I wrote another test to verify that the behavior is the same for Arrays:

require 'test/unit'

class ArrayTest < Test::Unit::TestCase

  def test_plus_equals_creates_new_object
    original_string = ["Hello"]
    hi = original_string
    assert_equal original_string.object_id, hi.object_id
    there = ["World"]
    hi += there
    assert_not_equal original_string.object_id, hi.object_id
  end

  def test_shovel_does_not_create_new_object
    original_string = ["Hello"]
    hi = original_string
    assert_equal original_string.object_id, hi.object_id
    there = ["World"]
    hi << there
    assert_equal original_string.object_id, hi.object_id
  end

end

So long story short, the reason why Ruby programmers prefer the shovel operator (<<) over the plus equals (+=) operator when building strings is to avoid creating multiple objects during the process. If there are subtleties that I am missing or if I am completely wrong, I would love to hear from people and improve upon what I have learned so far.

UPDATE: Thanks to @i82much for telling me how to embed code in wordpress.

UPDATE 2: Thanks again to @i82much, you can find out how to have source code displayed for different languages here

12 thoughts on “Ruby: Shovel vs. Plus Equals

  1. If the goal is to build up a large string, there’s a third way that’s also idiomatic ruby is on par with the shovel operator in terms of performance. I’m talking about building an array, and then using Array#join.

    Here’s a script that demonstrates what I’m talking about:


    require 'benchmark'

    N = 50_000

    Benchmark.bm do |bench|
    bench.report "shovel" do
    (0..N).inject("") {|memo,n| memo << "this is line #{n}\n" }
    end

    bench.report "plus-equals" do
    (0..N).inject("") {|memo,n| memo += "this is line #{n}\n" }
    end

    bench.report "join" do
    (0..N).map {|n| "this is line #{n}" }.join("\n")
    end
    end

    The output speaks for itself:


    phiggins@lihnucks ~/test $ ruby test_string_concat.rb
    user system total real
    shovel 0.090000 0.000000 0.090000 ( 0.085974)
    plus-equals 16.250000 0.130000 16.380000 ( 18.514102)
    join 0.090000 0.000000 0.090000 ( 0.088373)

    • Thanks for reminding me about benchmark Pete. I had learned about that somewhere (possibly in Beginning Ruby by Peter Cooper) before and completely forgotten about it. That is definitely useful. Thanks!

  2. For syntax highlighting, try

    var i = 0;

    If that didn’t come out right, it’s

    left bracket sourcecode language=”javascript” right bracket code left bracket slash sourcecode right bracket

  3. One downside of using the shovel operator to concatenate strings is that it doesn’t make a Rails model dirty. For example:

    e = Employee.first
    e.name << "sadf"
    e.name_changed? # returns false
    e.changed? # returns false

    Since the shovel operator doesn't create a new instance of the string, Rails doesn't seem to know that anything changed.

    • Jon,

      That’s good to know. It sounds like something that should change in Rails though, right? I do not know enough about Rails to comment but is there a reason why shove operator should not make the model object dirty?

      Thanks for the info!

Leave a comment

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