| Register | FAQ | Calendar | Search | Today's Posts | Mark Forums Read |
|
#1
| |||
| |||
| 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? -- Posted via http://www.ruby-forum.com/. |
|
#2
| |||
| |||
| On Wed, Aug 27, 2008 at 9:10 AM, Adam Akhtar <adamtemporary@gmail.com> 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? 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. |
|
#3
| |||
| |||
| Adam Akhtar 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. -- Posted via http://www.ruby-forum.com/. |
|
#4
| |||
| |||
| On 27.08.2008 09:10, Adam Akhtar 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. > 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? 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 |
|
#5
| |||
| |||
| Hi -- On Wed, 27 Aug 2008, Adam Akhtar 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 -- Rails training from David A. Black and Ruby Power and Light: Intro to Ruby on Rails January 12-15 Fort Lauderdale, FL Advancing with Rails January 19-22 Fort Lauderdale, FL See http://www.rubypal.com for details and updates! |
|
#6
| |||
| |||
| 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. -- Posted via http://www.ruby-forum.com/. |
|
#7
| |||
| |||
| > 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. -- Posted via http://www.ruby-forum.com/. |
|
#8
| |||
| |||
| 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 -- Posted via http://www.ruby-forum.com/. |
|
#9
| |||
| |||
| Hi -- On Thu, 28 Aug 2008, Adam Akhtar wrote: > 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. 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 -- Rails training from David A. Black and Ruby Power and Light: Intro to Ruby on Rails January 12-15 Fort Lauderdale, FL Advancing with Rails January 19-22 Fort Lauderdale, FL See http://www.rubypal.com for details and updates! |
|
#10
| |||
| |||
| On Thu, Aug 28, 2008 at 1:03 PM, David A. Black <dblack@rubypal.com> 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(p); // 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. |
![]() |
| Thread Tools | |
| Display Modes | |
In an effort to better serve ads to our visitors, cookies are used on objectmix.com. For more information, check out our Privacy Policy.