Appending to a string

If you come from another language, you might be tempted to use the += operator when appending to a string.

It works… but there is a better way to do it : the << method.

I have removed my initial claim about operator precedence as it isn’t really accurate. There is a much better reason to use << instead of += when appending to a string... something I didn't even realize (Thanks to Gregory). += will create a new String instance and will assign it to your left object. On the other hand, << will append the new string directly into your already existing left object. One could argue that += is only different than << and not better, but to me << is what you'll want to use 99% of the time (if not 100%) when appending to a String. I have yet to see a real case where one would want to "lose" it's existing String instance just to get a new one containing the exact same value.

You can also use the << method with arrays :

Be careful however when using << with Fixnum/Bignum instances. With these objects, the << method will shift the bits of your integer to the left. If you want to do a summation (append style that is), you will have to use +=

  • Gregory

    >> a = “foo”
    => “foo”
    >> a “foobar”
    >> a = “foo”
    => “foo”
    >> a.object_id
    => 1686724
    >> a “foobar”
    >> a.object_id
    => 1686724
    >> b = “foo”
    => “foo”
    >> b.object_id
    => 1668094
    >> b += “bar”
    => “foobar”
    >> b.object_id
    => 1657194
    >> a == b
    => true

    So actually, the two have different behaviors and should be used where appropriate, rather than preferring one over the other.

    Use String#= b is equivalent to a = a b

  • Gregory

    Hmm… the above seems to lost formatting. :-/

    I said it’s not precedence but the fact that String#+ and String#

  • Gregory

    Okay, your comment system sucks… hope you can reformat the above into a single comment. :)

  • Todd Werth

    It’s very true that you should use

  • Anselm

    The point of Gregory’s comment is that

    a += b

    generates a new object, while

    a << b

    appends b to the existing object a.

  • Frank

    Phew! I had a hard time to understand this… It’s true that my comment system is bad at keeping formatting. I’ll try to find some plugin that will fix the problem.

    Thanks for the info Gregory, I have updated the original post. However, I can’t see a real reason to use += instead of << when appending to a string…

  • Arne

    Supose you write a method that returns its argument with ‘+++’ appended to it :

    def m1(s); s + “+++”;end
    def m2(s); s << “+++”; end

    a=’abc’ #=> “abc”

    m1(a) #=> “abc+++”
    a #=> “abc”

    m2(a) #=> “abc+++”
    a #=> “abc+++”

    The point is that with << you’re modifying the instance, but maybe somewhere else there exists a reference to the same instance where the string is not expected to change. In general it can be good practice not to modify the objects passed into a method. (I’m overgeneralizing ofcourse).

    This is the reason that strings in Java (eww.. don’t mention the J-word…) are immutable. There’s a StringBuffer for when mutable strings are needed.

    But if you know what you’re doing, why not. The nice thing is that your algorithm might work unchanged with arrays and possible other objects due to ruby’s lovely duck-typing philosophy.

  • RSL

    If all you’re trying to do is print a concatenated string, though. I think I remember [from benchmarking] that puts “#{foo} #{bar}” is actually a bit faster than puts foo

  • RSL

    And it didn’t. :(

  • tim

    In general << can have unintended side effects and should be avoided. += will only modify the exact variable that you are working with.

    Say you're building up a string from a base which you want to remain the same.
    base = 'base string'
    a = base
    a << " some additional stuff "
    a << " more additional stuff "

    Unfortunately, you've also modified the value of base at this point.

  • Gib

    tim, I found this page with a google search because I was trying to figure out why a string of mine (“base” in your example) was changing, apparently in parallel with the contents of another string (“a” in your example).

    I was doing exactly what you describe there. Thanks for helping me understand what was going on.
    I changed it to
    base = ‘base string’
    a = ”;
    a << base;
    a << " some additional stuff "
    a << " more additional stuff "

    which fixed my problem.