views:

65

answers:

4

I am passing the reference of name to *mod_name*, I modify the referenced object from within the method but the change is not visible outside of the method, if I am referring to the same object from all locations how come the value is different depending on where I reference it?

name = "Jason"

puts name.object_id      #19827274

def mod_name(name)
  puts name.object_id    #19827274
  name = "JasonB"
end

puts name.object_id      #19827274

puts name                #Jason

String might be a bad example, but I get the same result even if I use a Fixnum.

A: 

In this case, the name = "JasonB" line is creating a new local variable named name and assigning "JasonB" to it, rather than modifying the string which was passed in.

Greg Campbell
So is there anyway, using the reference passed to modify the original name object from within the mod_name method?
Jason
@Jason: No. Ruby is pass-by-value. Always. You *can* obviously modify the object the reference points to (unless it is frozen or an immediate value), but you can not modify the reference.
Jörg W Mittag
@Jörg W Mittag: Ruby is not pass-by-value. it is allways "pass-by-reference".
Pedro Morte Rolo
@Pedro: Ruby does always pass parameters by value, as Jörg said. If it passed them by reference, then @Jason's code would have worked, since it would have had a reference to `name`. However, all values in Ruby are references. Consequently, Ruby is effectively a pass-references-by-value language, which makes it seem like it is passing things by reference in many (most?) cases. Apparently (according to Wiki: http://en.wikipedia.org/wiki/Evaluation_strategy), Ruby tends to call itself pass-by-reference, but this is directly at odds with the normal definition of the term (also at Wiki).
Antal S-Z
@absz - that was where I was getting confused, thought that I was passing a reference to the object and not the passing underlying object itself so that the name variables within and outside the method where both pointing to the same object / modifying the same object.
Jason
+3  A: 

As Greg mentions, in your example you're creating a new local variable called name that is shadowing your parameter. This is due to behavior called copy-on-write. If you wanted the function to affect the object the parameter references, you could use replace instead of doing an assignment, like this:

def mod_name(name)
  name.replace('JasonB')
end
Jimmy Cuadra
Jason
+1  A: 

mutating the content of a string :

def mod_name(name)
  print "%i %s\n" % [name.object_id, name]
  name[0..-1] = "what"
  print "%i %s\n" % [name.object_id, name]
  name << "ever"
  print "%i %s\n" % [name.object_id, name]
end

Also :

  • in your sample code you never call the mod_name function.

  • You seemed to believe that writing 'var = x' would change var's content. It can't. It can only change what object gets pointed to by var. Asking for its object_id before and after affectation would have showed that it was indeed another string.

  • There's no way to make this function work with Fixnums because Fixnums are immutable in ruby. You can't make any modification to a Fixnum. Worse, they're not even passed by reference and in some corner cases won't behave like proper objects.

+1  A: 

I think you have gotten answers to the question you asked. Maybe you need an answer to what would have caused you to ask this question.

name = "jason"

def mod_name(name)
  local_name = "jasonb"
end

puts name = mod_name(name)
puts name

Depending upon where this method lives (if it were in a class for example) maybe you would utilize an instance variable @name and depending upon the scope wouldn't have to be passed.

@name = "jason"

def mod_name()
  @name = "jasonb"
end

puts @name
Beanish