How to avoid passing by reference and how to copy objects

Hi after a bit of searching and reading im quite confused by this.

I first learnt C so used to being able to pass by reference or by value.
In Ruby its just by reference (so ive just found out after an hour of
chasing a bug).

I have an array of ojbects which are baisically acting like structures.
I want to pass the array to a function. This function will take the
array, make a new copy so as to protect the original from any changes.
Changes will be made to the copy and then the copy is returned.

How do i do that?

Ive looked dup but i dont think it works for objects… isnt there a
method to copy an object (i.e make new space in memory and put the data
there rather than juts pointing to the original objects address).

Id have thought it was necessary if you can only pass by reference…or
is the above considered bad design practice in ruby?

On Wed, Aug 27, 2008 at 9:10 AM, Adam A. [email protected]
wrote:

How do i do that?

The problem with the above approach is that an array holds also
references
to the contained objects. So if you are changing what objects the array
contains
your approach is fine. If you are changing the contained objects
themselves, then
you have the same problem, since dup makes a shallow copy:

irb(main):001:0> a = %w{one two three}
=> [“one”, “two”, “three”]
irb(main):002:0> a.map {|x| x.object_id}
=> [-606229548, -606229578, -606229608]
irb(main):003:0> b = a.dup
=> [“one”, “two”, “three”]
irb(main):004:0> b[0] = “new value”
=> “new value”
irb(main):005:0> a
=> [“one”, “two”, “three”]
irb(main):006:0> b
=> [“new value”, “two”, “three”]
irb(main):007:0> b.map {|x| x.object_id}
=> [-606260528, -606229578, -606229608]

As you can see here, both a and b are referencing the same
string objects in their second and third position. So the strings
“two” and “three” are the same objects in both arrays. If you
change those objects the change will be reflected in both
arrays:

irb(main):008:0> a[2].upcase!
=> “THREE”
irb(main):009:0> a
=> [“one”, “two”, “THREE”]
irb(main):010:0> b
=> [“new value”, “two”, “THREE”]

If you want to avoid this, you need b to be a deep copy of a.
One way to achieve it is with Marshal:

irb(main):011:0> c = Marshal.load(Marshal.dump(a))
=> [“one”, “two”, “THREE”]
irb(main):012:0> c.map {|x| x.object_id}
=> [-606348068, -606348078, -606348088]
irb(main):014:0> a[2].downcase!
=> “three”
irb(main):015:0> a
=> [“one”, “two”, “three”]
irb(main):016:0> b
=> [“new value”, “two”, “three”]
irb(main):017:0> c
=> [“one”, “two”, “THREE”]

Although you should read a bit more on Marshal to understand if
it suits your needs.

Hope this helps,

Jesus.

Adam A. wrote:

Hi after a bit of searching and reading im quite confused by this.

I first learnt C so used to being able to pass by reference or by value.
In Ruby its just by reference (so ive just found out after an hour of
chasing a bug).

I have an array of ojbects which are baisically acting like structures.
I want to pass the array to a function. This function will take the
array, make a new copy so as to protect the original from any changes.
Changes will be made to the copy and then the copy is returned.

How do i do that?

Ive looked dup but i dont think it works for objects… isnt there a
method to copy an object (i.e make new space in memory and put the data
there rather than juts pointing to the original objects address).

Id have thought it was necessary if you can only pass by reference…or
is the above considered bad design practice in ruby?

Have a look at this post:
http://al2o3-cr.blogspot.com/2008/08/object-arr.html it explains your
case a bit.

On 27.08.2008 09:10, Adam A. wrote:

I first learnt C so used to being able to pass by reference or by value.
In Ruby its just by reference (so ive just found out after an hour of
chasing a bug).

Well, it’s actually an advantage because passing a reference is usually
faster than passing an object by value.

Id have thought it was necessary if you can only pass by reference…or
is the above considered bad design practice in ruby?

Adding to the excellent advice: depending on what you have in your
structs you can also use Array#map to get a copy like this:

def f(x)
copy = x.map {|el| el.dup}
end

or even

def f(x)
x.map do |el|
# your calculation on each el
YourStruct.new some, more, values, like, el.length + 1
end
end

As I said, whether it’s safe depends on your data.

But I fully agree to Brian’s remark that something like this (deep copy)
is usually not done. It depends on your problem at hand which is the
best approach so if you provide a little more detail we might be able to
provide more concrete advice how to tackle your particular situation.

Kind regards

robert

Hi –

On Wed, 27 Aug 2008, Adam A. wrote:

Hi after a bit of searching and reading im quite confused by this.

I first learnt C so used to being able to pass by reference or by value.
In Ruby its just by reference (so ive just found out after an hour of
chasing a bug).

I know this sounds pedantic, but I think it’s really pass by value,
with the values being references.

In other words, if you do this:

a = [1,2,3]

you’re binding the identifier a to a reference to the array. If you
then do:

puts a

you’re passing the value of a (which is a reference to an array) to
puts.

In practical terms it doesn’t matter, but it helps make sense of, for
example, the fact that you can’t pass a reference-by-reference.

David

thanks everyone for that.

I typed along on irb to the examples presented and understand more about
rubys behaviour with “copying” stuff.

Its basically like (probably IS under the hood) Pointers.
so for some arrays a and b

a = b

thats basically copying the pointers themselves. So whatever changes i
make in A will be reflected in B.

a = b.dup

create some NEW pointers but which point to the same memory space. If i
edit one of the members it will be reflected in both a and b. However if
i substitute it for a totally different member im guessing new memory
space is allocated and a pointer points to that new memory space. Hence
the change is reflected in only one array.

to get a copy where new memory space for duplicate objects is creted,
you look towards marshall…

am i right (roughly) … hmmm pointers in C was always tricky.

thanks lex for that.
Im going to search for “ruby program design principles” or patterns
/best practices with regards to functions. When i learnt C (10 years ago
so its rusty) I was told to use pass by reference only when necessary. I
think the reason being bug tracking etc maybe the reasoning was similiar
ot that of not to over/misuse global variables.

So switching to ruby where pass by reference is the only choice seems to
be making my programming a little less smooth. Im just used to knowing
that the original value wont be changed. Sure I could dup or clone
everything but that seems to go against what ruby intends.

if anyone has a good link or book regarding such differences, their
implications and how to design along them rather than against (i.e. best
practice) please give us a shout. In the meantime ill go away and do
some searching and rejig my code.

thanks

create some NEW pointers but which point to the same memory space. If i
edit one of the members it will be reflected in both a and b. However if
i substitute it for a totally different member im guessing new memory
space is allocated and a pointer points to that new memory space. Hence
the change is reflected in only one array.

to get a copy where new memory space for duplicate objects is creted,
you look towards marshall…

am i right (roughly) … hmmm pointers in C was always tricky.

Here is a little example

class XTest

attr_accessor :test

def initialize
@test = 2
end

end

first = XTest.new
first.test = 10
second = first.clone
second.test = 11
puts first.test

So , If you want to preserve your parameters , clone them.

Hi –

On Thu, 28 Aug 2008, Adam A. wrote:

everything but that seems to go against what ruby intends.
See my earlier post, and Brian’s last one. It’s not pass by reference;
it’s pass by value, where the values are references. That’s actually
good news. For one thing, you don’t have to do (indeed can’t do)
pointer arithmetic. Every reference is exactly one step away from its
object. There are no references to references (which is why you can’t
do pass-by-reference in Ruby).

C is actually a poor point of reference (ha ha) for understanding Ruby
variables and references, because the two are so different. I’d
encourage you not to worry about how Ruby semantics align with C
semantics, because they pretty much don’t. In C you have this:

***p -> **p -> *p -> p

but in Ruby you always have this:

     b
     |
     v

a-> obj <- c

     ^
     |
     d

David

On Thu, Aug 28, 2008 at 1:03 PM, David A. Black [email protected]
wrote:

C is actually a poor point of reference (ha ha) for understanding Ruby
variables and references, because the two are so different. I’d
encourage you not to worry about how Ruby semantics align with C
semantics

Nevertheless C is only pass by value. That could help.

There’s no way in C to accomplish this

a = 7;
some_function(a);
// a is 7 for certain here

You can pass the address of a:

a = 7;
p = &a;
some_other_function§;
// a may be 5 now

but note that the argument of the function is p, it is not a. So you
are clearly just passing p by value.

Again, when some_other_function returns there’s no way p is pointing
to anything that is not a, because of pass by value semantics. In some
vague sense this second example has some resemblances to Ruby: you are
always passing ps in Ruby so to speak (that’s an analogy, it is clear
from the rest of the thread there are no actual pointers involved).

Through those ps, if the object is mutable you may change the state of
the object, but cannot change the very reference, the object pointed
at by p, the same way you cannot in C.

Java is pass by value as well.

On Thu, Aug 28, 2008 at 1:32 PM, Xavier N. [email protected] wrote:

There’s no way in C to accomplish this

a = 7;
some_function(a);
// a is 7 for certain here

Sorry I messed up the wording, I mean there’s no way some_function can
change the value of a in the caller.

Perl is only pass-by-reference by the way, sometimes it helps to see a
pass-by-reference example. So in Perl you can do this:

sub some_function { $_[0] = 5 }

my $a = 7;
some_function($a);

now $a is 5

Perl has references, but the “reference” in “pass-by-reference” is a
different word, it means the parameters of the function are aliases
of the arguments in the caller.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs