2

Why is variable a getting changed and how do I prevent it?

a = []       # => []
b = a        # => []
b << :hello  # => [:hello]
p a          # => [:hello]

# >> [:hello]

I see the responds to use clone, and wondering why the below works and in which situations .clone is needed and not needed

a = "string"   # => "string"
b =a           # => "string"
b = "changed"  # => "changed"
a              # => "string"
user2012677
  • 5,465
  • 6
  • 51
  • 113
  • 1
    There is no hash. – steenslag Jun 14 '19 at 00:47
  • Are hashes and array's the only places where pointers are in use? and all other variables not – user2012677 Jun 14 '19 at 01:04
  • They're all references. Some objects are mutable (arrays, hashes, strings, ...) but some are not (numbers, symbols, ...). – mu is too short Jun 14 '19 at 02:45
  • @muistooshort: Not necessarily (though OP shouldn't read this, as it might be confusing). `1` in CRuby is not a reference (in fact, no integer between `-4611686018427387904` and `4611686018427387903` is). `nil`, `false` and `true` are also not references. I think floats might not be either, but not 100% sure. They all transparently _behave as if they were_, and in another implementation they may well be. – Amadan Jun 14 '19 at 06:18
  • @Amadan But as far as *Ruby* is concerned, they're all references. The use (abuse?) of the bit pattern for numbers that fit in a pointer (sans "what is this thing" bits) is an implementation detail. AFAIK, symbols use similar trickery at the C level. In Ruby you can still say `6.some_method` so `6` is a reference like any other. I think we're splitting hairs here though :) – mu is too short Jun 14 '19 at 17:20
  • @muistooshort: `6.some_method` shows `6` is an object. It does not show it's a reference. I agree that Ruby does a fairly good job of pretending reference values and non-reference values are the same, and since only immutable values are non-reference values, it doesn't matter much. However, there is one consequence where you can't wave it away as "implementation detail": numbers and symbols don't have singleton classes, and can't define singleton methods. (`true`, `false` and `nil` also can't have a singleton class, but since they _are_ singletons, their class effectively masquerades as one.) – Amadan Jun 14 '19 at 22:33

3 Answers3

2

Why is variable a getting changed and how do I prevent it?

a = []       # => []
b = a        # => []
b << :hello  # => [:hello]
p a          # => [:hello]
# >> [:hello]

The variable a is not getting changed. The only way a variable can be changed is by assigning to it (ignoring reflection like Binding#local_variable_set), which you are not doing. Therefore, a doesn't change.

The object that is referenced by both a and b gets changed. But changing the object and changing the variable are two completely different things.

I see the responds to use clone, and wondering why the below works and in which situations .clone is needed and not needed

a = "string"   # => "string"
b =a           # => "string"
b = "changed"  # => "changed"
a              # => "string"

This works because you never change the object. You change the variable.

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
1

Why do you use a mutating method for the array and rebinding for the string and still expect they to behave similarly?

a = "string"   #⇒ "string"
b = a          #⇒ "string"
b << "changed" #⇒ "stringchanged"
a              #⇒ "stringchanged"
Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
0

As I understand its because of the memory usage.

When you initialize object, Ruby will first initialize object in the memory. Then, the variable points to that memory address. When you assign this variable to another one, that one will point to that address also

For example,

a = []
a.object_id # 70220203482480
b = a
b.object_id # 70220203482480

When you add new element, it means, you add the value to the array which initialized in memory, calling a and b will both show that array with new element.

a.push(1)
b # [1]

Let see the second example

c = 'reference'
d = c
c.object_id #70220203442960
d.object_id #70220203442960

c.capitalize! # 'Reference'
d # 'Reference'

If you assign d = 'new object', Ruby will create another object in the memory and give it value as string new object, and then, d will point to that new memory address

d = 'new object'
d.object_id # 70220203334840 (different one)
c # 'Reference' (cause c still point to the last object in memory)
quyetdc
  • 1,485
  • 1
  • 14
  • 24