Subject: Marshall - deep copies of variables
Author: Massaria
Posted: 01/10/2006 07:03PM
Thanks for your last reply 'test', got me going :-)
We've talked before on the oddity of some variables saving like '&id001' - because the .dup method only makes shallow copies - and you provided this link:
http://blade.nagaokaut.ac.jp/ruby/ruby-talk/30790
On the surface it does look very accessible, but I must admit it still eludes me how to use this Marshall business.
Lets say I have a hash like this:
my_hash = {gene1 => [a,b,c], gene2 => [d,e,f]}
I was gonna try to make a guestimate of how it would write up, but my grasp of it is so poor it'd be pure fabulation.
In addition, I haven't installed the ruby documentation, and their suggestion to 'go to the directory where you originally installed from and type 'make install-doc' is worthless when you don't remember which directory that is and have 3 directories with 'ruby.h', apparently none of them, or their parents, with a make file. shucks :-(
Thanks.
Mass
PS: I feel a bit bad about this turning into a ruby tutorial, but I figure as long as it's topics which will help the future newbies of tmud, it's acceptable.
reply
Subject: Marshall - deep copies of variables
Author: Tyche
Posted: 01/10/2006 08:46PM
Massaria wrote:
>
> Lets say I have a hash like this:
>
> my_hash = {gene1 => [a,b,c], gene2 => [d,e,f]}
>
Just by way of illustrating the problem through irb...
irb(main):002:0> my_hash = {'gene1' => ['a','b','c'], 'gene2' => ['d','e','f']}
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c"]}
irb(main):005:0> my_hash2 = my_hash
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c"]}
irb(main):006:0> my_hash2['gene1'] = ['x','y','z']
=> ["x", "y", "z"]
irb(main):009:0> my_hash
=> {"gene2"=>["d", "e", "f"], "gene1"=>["x", "y", "z"]}
irb(main):007:0> my_hash2
=> {"gene2"=>["d", "e", "f"], "gene1"=>["x", "y", "z"]}
irb(main):010:0>
Because assignment only creates a reference, when I modify the contents of my_hash2 I inadvertantly modify my_hash.
Using dup I can avoid this.
irb(main):017:0> my_hash = {'gene1' => ['a','b','c'], 'gene2' => ['d','e','f']}
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c"]}
irb(main):018:0> my_hash2=my_hash.dup
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c"]}
irb(main):019:0> my_hash2['gene1'] = ['x','y','z']
=> ["x", "y", "z"]
irb(main):020:0> my_hash
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c"]}
irb(main):021:0> my_hash2
=> {"gene2"=>["d", "e", "f"], "gene1"=>["x", "y", "z"]}
irb(main):022:0>
Marshall is pretty easy, although a bit wordy.
irb(main):010:0> my_hash = {'gene1' => ['a','b','c'], 'gene2' => ['d','e','f']}
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c"]}
irb(main):013:0> my_hash2=Marshal.load(Marshal.dump(my_hash))
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c"]}
irb(main):014:0> my_hash2['gene1'] = ['x','y','z']
=> ["x", "y", "z"]
irb(main):015:0> my_hash
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c"]}
irb(main):016:0> my_hash2
=> {"gene2"=>["d", "e", "f"], "gene1"=>["x", "y", "z"]}
irb(main):017:0>
Looks like they both work. Ah but wait looks can be deceiving..
irb(main):022:0> my_hash = {'gene1' => ['a','b','c'], 'gene2' => ['d','e','f']}
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c"]}
irb(main):023:0> my_hash2=my_hash.dup
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c"]}
irb(main):024:0> my_hash2['gene1'] << 'x'
=> ["a", "b", "c", "x"]
irb(main):025:0> my_hash
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c", "x"]}
irb(main):027:0> my_hash2
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c", "x"]}
The difference is instead of making the key reference a new array I added an element to the array referenced by the key. This shows dup's copy is shallow and only creates copies of the keys but doesn't copy the arrays the keys referenced. Sometimes this is what want, sometimes not.
The same as above using Marshal..
irb(main):028:0> my_hash = {'gene1' => ['a','b','c'], 'gene2' => ['d','e','f']}
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c"]}
irb(main):029:0> my_hash2=Marshal.load(Marshal.dump(my_hash))
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c"]}
irb(main):030:0> my_hash2['gene1'] << 'x'
=> ["a", "b", "c", "x"]
irb(main):031:0> my_hash
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c"]}
irb(main):032:0> my_hash2
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c", "x"]}
irb(main):033:0>
A true deep copy.
Since typing my_hash2=Marshal.load(Marshal.dump(my_hash)) is a royal pain in the bum, I could define a custom method to do it.
But you can do some neat Ruby kungfu magic like this.
irb(main):054:0>
class Object
def deepcopy
Marshal.load(Marshal.dump(self))
end
end
=> nil
irb(main):059:0> my_hash = {'gene1' => ['a','b','c'], 'gene2' => ['d','e','f']}
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c"]}
irb(main):060:0> my_hash2= my_hash.deepcopy
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c"]}
irb(main):061:0> my_hash2['gene1'] << 'x'
=> ["a", "b", "c", "x"]
irb(main):062:0> my_hash
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c"]}
irb(main):063:0> my_hash2
=> {"gene2"=>["d", "e", "f"], "gene1"=>["a", "b", "c", "x"]}
irb(main):064:0>
I reopened the class Object and declared a new method. Since everthing inherits from Object, now everything object in the Ruby world has a deepcopy method.
:-)
reply