The thing I’ve come to in my own understanding is that since everything is an object in Ruby, that means every variable is actually a pointer to an object in Ruby as well.
So when you pass in to the doit method, you are passing the reference into the local method variable data. Initially, data and in are pointing to the same object. But then you have to be aware of what things you are doing on the data variable. If it’s things with modify the same object originally point to by in, then the object in points to is being changed. Thus it looks like in is changed.
Doing other things can create new objects in ruby, though, so doing something to data that ends up creating a new object also ends up making in look unchanged when doit exits, which is so.
So let’s try this.
def doit2(data)
data.shuffle
end
According to the docs, shuffle creates a new array. So:
$ pry
[1] pry(main)> start_data = [1,2,3,4,5].freeze
=> [1, 2, 3, 4, 5]
[2] pry(main)> a_ary = start_data
=> [1, 2, 3, 4, 5]
[3] pry(main)> def doit(data)
[3] pry(main)* data.shuffle
[3] pry(main)* end
=> nil
[4] pry(main)> doit(a_ary)
=> [2, 4, 5, 3, 1]
[5] pry(main)> a_ary
=> [1, 2, 3, 4, 5]
[6] pry(main)> a_ary.object_id
=> 70307654300780
[7] pry(main)> doit(a_ary).object_id
=> 70307649978420
[8] pry(main)> doit(a_ary).object_id
=> 70307650161900
So you can see that .shuffle is creating a new object each time.
But remember we froze the source data up there? a_ary is also pointing to the frozen array, so when you change doit to something like this:
[9] pry(main)> def doit(data)
[9] pry(main)* data.shift
[9] pry(main)* end
=> nil
[10] pry(main)> a_ary
=> [1, 2, 3, 4, 5]
[11] pry(main)> a_ary.object_id
=> 70307654300780
[12] pry(main)> b_ary = doit(a_ary)
RuntimeError: can't modify frozen Array
from (pry):12:in `shift’
It fails because we tried to change a frozen object.
Now if we do this:
[13] pry(main)> b_ary = doit(a_ary.dup)
=> 1
[14] pry(main)> a_ary
=> [1, 2, 3, 4, 5]
[15] pry(main)>
doit is working on a new object that isn’t frozen.
···
On Nov 12, 2013, at 7:09 PM, gvim <gvimrc@gmail.com> wrote:
In Perl I used to do this:
print 'Enter data: ';
chomp(my $in = <STDIN>);
sub doit {
my $data = shift;
.........
return $data;
}
doit($in);
In Ruby the equivalent seems to be:
puts 'Enter data: '
in = gets.chomp
def doit(data)
........
return data
end
doit(in)
However, Ruby passes arguments by reference so it seems the variable 'data' is always accessing and changing the file-global variable 'in'. Is there a more Perl-like, way of lexicalising the scope of variables passed as arguments to functions?
gvim