Concatenation in Ruby and . object_id

Asked

Viewed 982 times

4

Hello, my friends!

I was studying Ruby and reading the concatenation methods I noticed a slight difference. When I tested the first method using "+", I noticed that when using the .object_id it generates me an id before, and after concatenation it passes me a different id.

Using the method "+":

x = "Método de"
puts x.object_id
x = x + "concatenação"
puts x
puts x.object_id

Terminal result:

47068325481320
Método de concatenação
47068325481120

Already using the shovel (<<), I noticed that it does the concatenation the same way, but it returns the same object_id:

Using the method "<<":

x = "Método de "
puts x.object_id
x << "concatenação"
puts x
puts x.object_id

Terminal result:

47453902360060
Método de concatenação
47453902360060

I would like to know why when using "+" to concatenate strings it generates a new object, and in both cases before and after concatenation remains the same variable 'x'.

What’s the influence of that on my system?

3 answers

6


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

3

Adding to Other Responses: When You Use <<, because you are changing the object itself, it may be that you change a string passed to a function from within it and it has outside effects.

For example:

def muda_string(string)
  string << "bar"
  # Faz alguma coisa com a string aqui...
end

a = "foo"
muda_string(a)

puts a # => foobar

It may seem obvious, but it goes unnoticed sometimes and can cause some very difficult side effects to debug.

0

In the first case you are giving a value to the variable "x", so it generates a different id. In case you are creating again the variable "x"

In the second case, you are adding the value to the existing variable.

  • Then the "<" method would be the most efficient in terms of memory/speed?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.