I was content to jet-ski across the surface of an understanding of variables in Ruby until the grimy tentacles of Leetcode forced me below the surface. Several challenges in their curated list of top interview questions specified that I write a method which would modify the value passed in as an argument "in-place"; that is, rather than having the method return a new, modified value, the original value needs to be (destructively) changed. In these cases Leetcode would evaluate the value of the variable which was passed as an argument to your method and disregard the method's return value, which I'd never encountered before.
Uttering the eternally bad-idea phrase "well, that seems simple," I dove in and tried to get them to work. What transpired was comic gold: Three-Stooges-level antics wherein I kicked my shins on every possible surface trying to intuit why the original value would sometimes be modified, sometimes not, and inconsistently between different methods. I found my way to solutions, but now knew that I had gaps in my understanding about how variables work on a deeper level in Ruby (and beyond).
In this article I'll document my process of filling in those gaps, and would love to bring you along with me on this odyssey of the mind.
I'm deeply indebted to the following articles, which I'd highly recommend you read if you're interested in this subject and want more detail:
- "Variable References and Mutability of Ruby Objects," Pete Hanson at Launch School
- "The Basics of Variable Assignment in Ruby," Tim Freeman at Techtrument
- "The Complete Guide to Create a Copy of an Object in Ruby," Mehdi Farsi at Rubycademy
My functional understanding of variables before this deep dive was that they act like a labelled container. You can put a thing in the container, and retrieve that thing by referring to its label.
In this mental model, if I assign a string to a variable like so:
name = "Daniel"
The variable name
is a box labeled "name" which holds the string object "Daniel."
The problem that I ran into with this mental model is that it doesn't account for what happens to that string if I do this:
another_name = name
I know that the variable another_name
now holds a string of "Daniel." To extend the illustration, I dump what's in the "name" box into the other. But is that the same string as the one in the name
box, or a copy? If I change one, does the other change?
The reality is more complex, but resolves those questions. The variable doesn't hold or contain the value, but instead holds (or is "bound" to) a reference to the place in memory that holds the value.
At my university, our student center had a wall of mailboxes which each had a four-digit number (e.g., "1123," "4512," etc.) which functioned like your apartment address. On a couple occasions I was tasked with distributing flyers for school events and got to see the other side of the wall, where each mailbox was labeled with both the mailbox number and the student's name.