Ruby shovel operator: What the?!

This is taken from the Ruby Koans. It’s the shovel operator, and it appends stuff to a string.


    original_string = "Hello, "
    hi = original_string
    there = "World"
    hi << there

So I'm totally down with the idea that hi now equals "Hello, World". No problem. But in fact, original_string also now equals "Hello, World". That is totally messed up! :)

But seriously. What is up with that? is there way to not find this just... just... shocking?!


13 Comments on “Ruby shovel operator: What the?!”

You can track this conversation through its atom feed.

  1. Todd Kaufman says:

    In line 2 you create a pointer to the original original string, not a new object. So both hi and original_string point to the same thing. Any changes made via hi or original_string will affect the same underlying object.

    Make sense?

  2. Angela says:

    It does, and I figured that was the case, but I still find it astounding. Wonder how that’s going to become intuitive, but I suppose everything does, eventually, right? :)

    But isn’t it dangerous? Seems like a really likely place to get into serious trouble. Knee deep in code, how would I know if something is a legit variable or a pointer to something else?

    Is there some other way besides alpha = beta to assign a value without just creating a pointer?

    (Is this where you say “Relax, grasshopper. All will become clear in time”?) :)

  3. Tweets that mention Ruby shovel operator: What the?! at My Agile Education -- Topsy.com says:

    [...] This post was mentioned on Twitter by Jose Manuel Beas. Jose Manuel Beas said: RT @angelaharms: A Ruby question: Ruby shovel operator: what the? http://bit.ly/RubyShovel [...]

  4. Todd Kaufman says:

    Prolly should relax, but the important thing is that all variables are just pointers to something. You can get a new object based on a current one via clone or dup. See irb fun below:

    >> a = "Angela"
    => "Angela"
    >> b = a
    => "Angela"
    >> b < "Angela is learning ruby!"
    >> puts a, b
    Angela is learning ruby!
    Angela is learning ruby!
    => nil

    versus

    >> a = "Angela"
    => "Angela"
    >> b = a.dup
    => "Angela"
    >> b < "Angela is learning ruby!"
    >> puts a, b
    Angela
    Angela is learning ruby!
    => nil

  5. Sean McMillan says:

    This appears to be the same semantics as python, where I learned this alternate formation:

    Stop thinking of = as an assignment.

    The = operator performs a binding operation, tying a name (on the left,) to an object (on the right.) Values are never changed, only bindings are changed.

    Thinking of it in terms of name binding instead of assignment makes it more intuitive for me.

  6. Shih-gian Lee says:

    Ruby String object is different than the String in language like Java. One thing to notice is Ruby String is mutable.

    In Java, if we have:

    String a=”Hello”;
    String b=a;
    String c=b + ” World”;

    We will have the following output:
    Hello //b
    Hello World //c

    The “+” operator returns a new instance of String because String is immutable.

    In Ruby, since String is mutable, any variable that is pointing to the same String will be effected. This design is consistent with other objects in Ruby. If you want a Ruby object to be immutable, we can use String#frozen to prevent it from being changed.

  7. rdm says:

    “Is there some other way besides alpha = beta to assign a value without just creating a pointer?”

    I think when you pass arguments to methods, and those arguments are references to objects, the method gets those references to objects.

    In other words:

    hammer.pound(nail)

    can bend the nail (if nails are things that can be bent).

    This is almost the essence of object oriented programming, I think.

  8. xtoddx says:

    You’re looking for the ‘dup’ method.

    irb(main):001:0> original_string = “Hello, ”
    => “Hello, ”
    irb(main):002:0> hi = original_string.dup()
    => “Hello, ”
    irb(main):003:0> there = “World”
    => “World”
    irb(main):004:0> hi < “Hello, World”
    irb(main):005:0> hi
    => “Hello, World”
    irb(main):006:0> original_string
    => “Hello, “

  9. Jon Kern says:

    If you step back and don’t think so hard (or with the biases of other languages), why would you expect any different outcome?

    original_string = “Hello, ”
    hi = original_string
    there = “World”
    hi << there

    You are appending ‘there’ to ‘hi’ and it stands to reason that you end up with the two strings as “Hello, World”

    Maybe you were expecting Ruby to be more difficult?

    What I have learned — and attempt to imitate — is that Ruby code should be obvious and comfortable.

  10. Ron Jeffries says:

    Has anyone noticed that hi += there does NOT modify original_string,
    but hi << there DOES?

    That is at least interesting if not downright weird.

    1. James says:

      When you type

      hi += there

      you are making hi point to the string that you get when you concatenate “Hello, ” and “World”. You have created a new object and now hi is pointing to it. If you type

      hi << there

      you are slapping "World" onto the end of the string that hi points to. original_string points to the same string object.

      The big difference between the two operators is this:

      += creates a new string object.

      << adds characters to an existing object.

  11. Season of Ruby – Learning the Syntax « Old Dog, New Tricks says:

    [...] moment with the shovel operator ” <<” versus “+=”, but I am not alone there.  After Googling around it made sense and this article about the performance differences was a [...]

  12. Adan Byerly says:

    And we don’t have a very monopoly. We have business. There’s a difference.
    Don’t get worried about people stealing your thinking. If your ideas are any good, you need to ram them down people’s throats.

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>