RubyCademy - Lesser-known facts about variables in Ruby

Variables, arguments, references, copy, mutation, and reassignment.

The complete guide to understanding what happens when you pass a variable value as an argument of a method call!

Introduction

This topic is surprisingly underestimated by the Ruby & Ruby on Rails community.

We often hear: "Values are passed by reference. Ok". and that's it! We move on to the next topic.

It's a pity. There's deeper learning to uncover.

What is a variable?

Ruby is a pure object-oriented programming language, meaning that everything is an object in the Ruby language.

So what you commonly call a variable value is an object.

Knowing this, here is the simplest definition of what a variable is:

A variable is a label that points to a specific object.

Two Labels, One Object

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

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

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

We can also see that arg points to the 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, let's see what happens when we deliberately reassign another object to arg.

Replacing the value of the private copy

Here, var and arg point to the 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 to the method call.

A more verbose way to see the changes is to flatten the scope using define_method to access the var outer variable.

Here we can compare the object IDs before/after the reassignment.

Mutating the value of the private copy

Here, we pass export_settings as an argument of trigger_export_with_settings.

Within this method, we modify settings which is a private copy that points to the same value as export_settings.

By calling the Hash#[]= assignment method, the hash is mutated.

So as export_settings points to the same instance of Hash as settings, the changes are reflected on export_settings after the call to trigger_export_with_settings(export_settings).

In this particular case, it'd be better to use Hash.merge which doesn't modify self and returns a new hash instead.

Conclusion

A recap of the main concepts covered in this issue:

  • A variable is a label that points to a specific object.

  • An argument:

    • is a private copy of a variable passed to a method.

    • points t0 the same value as the variable it refers to.

  • A private copy no longer points to the same value as a variable when a new value is reassigned to it.

  • mutating the value of a private copy is like mutating the value of the variable it refers to.

Now that you're more familiar with Variables, arguments, references, copy, mutation, and reassignment, you'll be more aware of the code you write within your methods!

Hope you enjoyed this issue!

If you’re serious about taking your Ruby skills to the next level, visit RubyCademy for resources that go beyond the basics.

For those ready to go deep, our Advanced Ruby Masterclass is now open for early-bird registration, with the next session starting in January 2025. Limited seats are available—don’t miss out!

Voilà!