+= on arrays

378 views

What is the return value of the following Ruby code?

def my_method(a)
  a += [4]
end

a = [1, 2, 3].freeze

my_method(a)

a # => ???

The correct answer is

[1, 2, 3, 4]

It raises FrozenError

[1, 2, 3]

Unlock Your Ruby Potential

Subscribe to RubyCademy and get free access to all our courses, plus hundreds of fun Ruby cards, quizzes, guides, and tutorials!

Explanation

Frozen Array

Array#+ does not modify self. Indeed, it simply returns a new instance of Array that is reassigned to a.

a = [1].freeze

a.object_id # => 17320

a = a + [2] # => [1, 2]

a.object_id # => 30460

So the first frozen array assigned to a is replaced by the new Array returned by Array#+.

Replacing the value of a private copy

Firstly, let's define what is a variable in Ruby: a variable is a label that points to a specific object.

Now that we're more familiar with what a variable is in Ruby, let's see what happens when a variable value is passed as an argument of a method call.

In Ruby, when an object is passed as an argument of a method call, a private variable that points to the exact same object is created

var = Object.new

var.object_id   # => 7320

def my_method(arg)
  arg.object_id # => 7320
end

my_method(var)


Here, var points to an instance of Object with the object ID 7320.

We can also see that arg points to the exact same object as var during the call to my_method(var).

In this case, we say that arg is a private copy of var.

Now, what happens when we try to change the value of a private copy?

var = Object.new

var.object_id   # => 7320

def my_method(arg)
  arg.object_id # => 7320

  arg = Object.new

  arg.object_id # => 20600
end

my_method(var)

var.object_id   # => 7320

Here, var and arg point to the exact same instance of Object with object ID 7320.

Then a new instance of Object is reassigned to arg.

So, at this moment var and arg point to 2 different instances of Object.

That's why, once the method call is terminated, var still points to the same object as prior the method call.

Unlock Your Ruby Potential

Subscribe to RubyCademy and get free access to all our courses, plus hundreds of fun Ruby cards, quizzes, guides, and tutorials!

RubyCademy ©