Why Is the Shovel Operator (≪≪) Preferred Over Plus-Equals (+=) When Building a String in Ruby

Why is the shovel operator () preferred over plus-equals (+=) when building a string in Ruby?

Proof:

a = 'foo'
a.object_id #=> 2154889340
a << 'bar'
a.object_id #=> 2154889340
a += 'quux'
a.object_id #=> 2154742560

So << alters the original string rather than creating a new one. The reason for this is that in ruby a += b is syntactic shorthand for a = a + b (the same goes for the other <op>= operators) which is an assignment. On the other hand << is an alias of concat() which alters the receiver in-place.

Trying to understand the shovel operator with strings

When you set hi = original_string your hi variable is just a new variable pointed at the same object. If you look at hi.object_id and original_string.object_id you will find they are the same. If you want a clone of an object that you can manipulate without impacting the
original_string, you'll need to say something like hi = original_string.clone or hi = original_string.dup.

I'd like an explanation of a behavior in Ruby that I ran across in the Koans

In ruby, everything is a reference. If you do foo = bar, now foo and bar are two names for the same object.

If, however, you do foo = foo + bar (or, equivalently, foo += bar), foo now refers to a new object: one that is the result of the computation foo + bar.

Ruby differences between += and to concatenate a string

The shovel operator << performs much better than += when dealing with long strings because the shovel operator is allowed to modify the original string, whereas += has to copy all the text from the first string into a new string every time it runs.

There is no += operator defined on the String class, because += is a combined operator. In short x += "asdf" is exactly equivalent to x = x + "asdf", so you should reference the + operator on the string class, not look for a += operator.

Why does double shovel in Ruby not mutate state?

If we convert your a << b << c construct to a more method-ish form and throw in a bunch of implicit parentheses the behavior should be clearer. Rewriting:

greeting = "Hi there, " << name << "?"

yields:

greeting = ("Hi there, ".<<(name)).<<("?")

String#<< is modifying things but name never appears as the target/LHS of <<, the "Hi there ," << name string does but name doesn't. If you replace the first string literal with a variable:

hi_there = 'Hi there, '
greeting = hi_there << name << '?'
puts hi_there

you'll see that << changed hi_there; in your "Hi there, " case, this change was hidden because you were modifying something (a string literal) that you couldn't look at afterwards.

The following program prints the value of the variable. Why?

In case of ambiguity when compiler finds a variable and method with same name in same scope, it gives precedence to the variable.

To call the method explicitly, send empty parens ()

hello_world = 'Hello Ruby World' 

def hello_world
'Hello World'
end

puts hello_world()

or provider an explicit receiver to the method, in this case, using self

self.hello_world

Edit:
As sepp2k advised in comments below, self.hello_world would not work with a ruby(.rb) file. Just to try, you can dynamically dispatch the method with send:

send(:hello_world) #or
method(:hello_world).call

Why I get +1 of my string length when I use gets?

I just to use the .chomp after the gets.
I'm feeling so dumb...

str = gets.chomp

Without it the gets method includes a newline character at the end

Array equation explanation

To break anything down line by line one could use REPL:

*a, b = [1, 2, 3, 4]
#⇒ [1, 2, 3, 4]

a
#⇒ [1, 2, 3]

b
#⇒ 4

Using splat operator, we have decomposed the original array to new array and the single value. Now everything is crystal clear: a[b-2] which is a[2], which is in turn 3 (check a array.) and b is still 4.

3 + 4
#⇒ 7


Related Topics



Leave a reply



Submit