4

Consider the following code in ruby, assume I called prestart from somewhere:

def tester(process_name, *host_list)
  hosts = []
  hosts = host_list[0]
  hosts[0] = nil
end

def prestart(process_name, *host)
  host_list = ['192.168.1.1', '192.168.1.2'] 
  puts host_list.inspect  # -> ['192.168.1.1', '192.168.1.2']
  tester(process_name, host_list)
  puts host_list.inspect  # -> [nil, '192.168.1.2']
  abort
end

How did it become nil? Is this how ruby works? If yes, how do I make sure it doesn't effect the caller?

KL-7
  • 46,000
  • 9
  • 87
  • 74
Shrinath
  • 7,888
  • 13
  • 48
  • 85

1 Answers1

3

Arrays are objects, and therefore are past by reference. If you want to change it without affecting the original, you need to duplicate it by calling .dup on it. You can do it either in the caller or in the called method.

Idan Arye
  • 12,402
  • 5
  • 49
  • 68
  • Absolutely right!! I missed the part where they say array is an obj :) – Shrinath Apr 25 '12 at 11:18
  • Arrays are mutable objects in most high level languages(except pure functional languages, where nothing is mutable). It should also be noted that in Ruby, unlike most high level languages, strings are also mutable objects. – Idan Arye Apr 25 '12 at 11:27
  • You mean to say if you pass strings in above example, it behaves similarly? effecting in caller? – Shrinath Apr 25 '12 at 11:53
  • 1
    If you change the string itself. That is - if you do something like `str[0]='e'`, the original string will be changed, but if you do `str=nil`, the original string will be intact - because you only changed the reference. Also note that many string functions in Ruby has two variations - mutating and non-mutating. The mutating variations ends with ! and changes the original string, and the non-mutating doesn't. So `str.reverse` will return the reverse string while keeping the original intact, and `str.reverse!` will reverse the original. This is also true for many other data structures in Ruby. – Idan Arye Apr 25 '12 at 12:06
  • -1. Nothing is ever passed by reference in Ruby. Ruby is pass-by-value. Always. No exceptions. No ifs. No buts. – Jörg W Mittag Apr 26 '12 at 01:13
  • @Jörg W Mittag: http://stackoverflow.com/questions/1872110/is-ruby-pass-by-reference-or-by-value I jumped the boat after this experience... Please abandon your ship now :) – Shrinath Apr 26 '12 at 05:52
  • @Shrinath: It's pretty obvious that neither the person who asked the question nor the person who answered it nor the 19 people who upvoted the answer have the slightest clue what *pass by reference* or *pass by value* mean. If you want to know whether Ruby is *pass by reference* or *pass by value*, just try it out: `def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}"`. – Jörg W Mittag Apr 26 '12 at 08:59
  • @Jörg W Mittag: Read the accepted answer here in answer to your previous comment, http://stackoverflow.com/questions/7688391/why-doesnt-this-work-if-in-ruby-everything-is-an-object – Shrinath Apr 26 '12 at 16:41
  • Do you still stand by what you said after reading the 2nd, 3rd and 4th quote of the accepted answer? – Shrinath Apr 26 '12 at 16:42
  • Also, [read this](http://www.ruby-forum.com/topic/41160), long read, but worth it! – Shrinath Apr 26 '12 at 16:48
  • @JörgWMittag It's a matter of terminology, really. In Ruby, objects variables **are** references, so when you pass an object to a function, you actually pass it's reference. Technically, you pass the *object's reference* by value, but the abstraction is that the *object itself* is passed by reference. – Idan Arye Apr 26 '12 at 18:33