Confused by scope in ruby

M

Mischa Fierer

Hello,

I've been writing in ruby for a bit, but ran into something while
working on a project that struck me as weird, and could not find a ready
explanation.

Sorry if this is something super basic...

Here is a simplified example.

My question is: Why is the hash not empty at the end?

class Hmmm
def why_not_empty?
hash = {}
puts "Start: hash = #{hash.to_s}"
[1, 2, 3, 4, 5].each do |num|
put_in_hash(num, hash)
end
puts "End hash:\n#{hash.to_s}" # i would expect this to be {}
end

def put_in_hash(num, hsh)
hsh[num.to_s] = "hello from hash index #{num}.\n"
return nil
end

def number
num = 2
puts "Start number: #{num}"
change_number?(num)
puts "End number: #{num}"
end


def change_number?(num)
num = 3
end
end

@a = Hmmm.new
@a.why_not_empty?
@a.number



Output:
Start: hash =
End hash:
1hello from hash index 1.
2hello from hash index 2.
3hello from hash index 3.
4hello from hash index 4.
5hello from hash index 5.
Start number: 2
End number: 2

The number, as I would expect, stays at two, but the hash is actually
changed by the method, as if I were passing it a pointer in C or
something...
 
S

Sebastian Hungerecker

Mischa said:
The number, as I would expect, stays at two, but the hash is actually
changed by the method, as if I were passing it a pointer in C or
something...

Well, that's exactly what's happening at C level - in both cases. The
difference is that if you do foo[bar] = baz or foo.method_that_changes_foo!
then you change the object that foo points to (so all other variables that
point to the same object will also reflect those changes), but if you do
foo = bar, you're just changing the pointer, i.e. foo now points to wherever
bar points to and the object that it previously pointed to is unchanged.

HTH,
Sebastian
 
T

Thomas B.

Mischa said:
Hello,

I've been writing in ruby for a bit, but ran into something while
working on a project that struck me as weird, and could not find a ready
explanation.

Assigning a value to a parameter simply assigns a new variable to the
letter, and adding something to a hash modifies the existing object,
referenced by the variable. Similarily if you pass a string to a method
def change(s) and inside the method do:
s="abc" # does not change the original object
s+="abc" # does not change the original object, because it is equivalent
to s=s+"abc"
s<<"abc" # does change the outside object because it is an in-place
modification
s.upcase! # does change
s=s.upcase # does not

Have a look: http://al2o3-cr.blogspot.com/2008/08/object-arr.html

TPR.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,710
Latest member
bernietqt

Latest Threads

Top