ac7v
ac7v

Reputation: 27

Variable value reassigned in ruby unintentionally

I'm still learning basics of ruby so I thought I'd attempt to make a multiplication table

x = (0..7).to_a
y = []
x.each { y << x }

y is now an 8x8 array where each row is equal. These are just placeholder values that I don't want, so I attempt to iterate through the array indices to change the values.

x.each { |i| y[i][i] = i * i }

At this point, y becomes an array containing 8 columns of [0, 1, 4, 9, 16, ...]. I understand why I'm only receiving squared values, but I don't understand why y[1][3], for example, is altered at all, when I'd only expect values at indices such as [1][1], [2][2] to be altered.

And furthermore, the value of x is reassigned to [0, 1, 4, 9, 16, ...] as well, even though I never intentionally reassigned its value. By the above portion of code, its value is reassigned automatically, and I cannot understand why.

I could always look up another method for making such a table myself, but I want to understand what's happening to x that causes it to change its value and why iteration through the indices doesn't behave as expected. I'll move on to iterating more properly over each index of the 2D array when I can grok why my simpler attempt is producing an invalid output. I'd like to figure out this rather basic task on my own, but I've hit a roadblock for now.

Upvotes: 1

Views: 120

Answers (1)

Gareth McCaughan
Gareth McCaughan

Reputation: 19971

What you've put in y is 8 references to the exact same object x. So when you alter y[1][1], that is the same thing as x[1], which is the same thing as y[2][1] and y[3][1] and so on.

The value of x isn't getting reassigned. Rather, x is an 8-element array; this object is an element of y eight times as well as being the value of x; each iteration of the each is modifying the contents of that array.

This is pretty counterintuitive if you're not used to it. Perhaps the following gruesome analogy will help. Suppose you have just started up a secret society, and at the moment you are the only member. (It's a very secret society.) In particular: You are the President of the society, and its Secretary, and its Treasurer. You also have a job; you are, let's say, the CEO of Microsoft.

Now, a member of a rival secret society comes and breaks the left toe of the President of your secret society. (Apparently it wasn't quite secret enough.) Another comes and breaks the right kneecap of the Secretary. Another smashes out the teeth of the Treasurer. And now, lo, it turns out that the CEO of Microsoft has suffered all these indignities. How can that be? No one ever told anyone to break the kneecaps of the CEO of Microsoft!

Of course there's nothing difficult about this: the very same person can fill all those roles; you get the exact same person if you ask for the President of the Mangrove-Throat-Wobbler Society as if you ask for its Secretary, or if you ask for the CEO of Microsoft.

In Ruby (and many other languages like it), the relationship between a variable and its value, or a position in an array and the thing held there, is much more like the relationship between an official post and its holder than, e.g., like the relationship between a box and its contents. The exact same thing can be the value of many variables, just as the exact same person can be President and Secretary and Treasurer and Grand Pooh-Bah.

Upvotes: 5

Related Questions