How did you find out yourself:
The method +=
generates and makes the variable point to a new String
:
# exemplo mostra id mudando para uma mesma variável
irb(main):010:0> minha_var = "hello"
irb(main):011:0> minha_var.object_id # => 17187071060
irb(main):012:0> minha_var += " world"
irb(main):013:0> minha_var.object_id # => 17187027180
The method <<
changes the object itself:
# exemplo mostra id permanecendo inalterado
irb(main):014:0> outra_var = "foo"
irb(main):015:0> outra_var.object_id # => 17186991840
irb(main):016:0> outra_var << "bar"
irb(main):017:0> outra_var.object_id # => 17186991840
And what difference does it make?
In my opinion, the difference that can bring practical problems and introduce bugs is that if an assignment is made and then the method is used <<
to change the value of a variable, the variable that received the value previously will also be changed, because the two share the same reference for the object.
Using Concat:
irb(main):001:0> foo = "foo"
=> "foo"
irb(main):002:0> bar = foo
=> "foo"
irb(main):003:0> foo << "bar"
=> "foobar"
irb(main):004:0> bar
=> "foobar"
# bar foi alterado quando alteramos foo
irb(main):005:0> foo.object_id == bar.object_id
=> true
Using +=:
irb(main):006:0> foo = "foo"
=> "foo"
irb(main):007:0> bar = foo
=> "foo"
irb(main):008:0> foo += "bar"
=> "foobar"
irb(main):009:0> bar
=> "foo"
# += gerando uma cópia, bar mantém seu valor original
irb(main):010:0> foo.object_id == bar.object_id
=> false
Difference in performance
Using the module benchmark
, we can clearly see the difference that makes changing an object or creating and allocating memory to a new:
require "benchmark"
n = 100000
Benchmark.bmbm do |x|
x.report("<<") do
foo = "foo"
n.times do
foo << "bar"
end
end
x.report("+=") do
foo = "foo"
n.times do
foo += "bar"
end
end
end
Upshot:
Rehearsal --------------------------------------
<< 0.023438 0.007812 0.031250 ( 0.019828)
+= 4.992188 2.570312 7.562500 ( 7.740998)
----------------------------- total: 7.593750sec
user system total real
<< 0.015625 0.000000 0.015625 ( 0.018702)
+= 5.007812 1.132812 6.140625 ( 6.176764)
Material shamefully taken from the following pages:
Why is the Shovel Operator (<<) Preferred over plus-equals (+=) when building a string in Ruby?
A Little More About Strings
Another interesting page about performance and strings:
Never create Ruby strings longer than 23 characters
Then the "<" method would be the most efficient in terms of memory/speed?
– Alan Maxwell