From: Brian Candler Date: 2008-09-20T04:19:47+09:00 Subject: Re: why one array continues to grow after repeated call Randy Kramer wrote: > Hmm, don't know how to express this properly (and maybe it's way off > base), but are you hinting at the idea that if I were to try []= on an > immutable data type, then the behavior would not be an assignment. []= is *never* an assignment. If you call []= on an object which is immutable, then by definition it cannot mutate. But there was never any requirement for it to have a method called []= in the first place, and even if it did, there was no requirement for it to mutate. Sure, I can write: irb(main):001:0> str = "hello" => "hello" irb(main):002:0> str.freeze => "hello" irb(main):003:0> str["h"] = "HHH" TypeError: can't modify frozen string from (irb):3:in `[]=' from (irb):3 from :0 but that error is nothing to do with the method being called []=; it's simply because the string is frozen. I get the same if I do: irb(main):004:0> str << "foo" TypeError: can't modify frozen string from (irb):4:in `<<' from (irb):4 from :0 But I *can* write: irb(main):005:0> str = "goodbye" => "goodbye" *That's* an assignment. str now points to a completely different object. The fact that the old string was frozen is irrelevant. It will be garbage-collected later, if no-one else also has a reference to it. > (I'm > not sure what it would do--report an error, create a new object with a > different object_id? (Some quick experiments with a constant seem to > indicate that is the case (actually, it does both).) Or it could do nothing. Depends what you define []= to do. If no []= method has been defined, then you'll get an "undefined method" error. irb(main):002:0> class Foo irb(main):003:1> end => nil irb(main):004:0> Foo.new[3] = 4 NoMethodError: undefined method `[]=' for # from (irb):4 from :0 Note that you'll get this error whether or not Foo has a "[]" method. They're entirely independent. > irb(main):224:0> Const = 3.14 > (irb):224: warning: already initialized constant Const > => 3.14 > irb(main):225:0> Const.object_id > => -606494436 > irb(main):226:0> Const = 3.00 > (irb):226: warning: already initialized constant Const > => 3.0 > irb(main):227:0> Const.object_id > => -606517176 You've observed that 3.00 and 3.14 are different objects. "Const" is not an object. At first, Const held a reference to 3.14; and then it held a reference to 3.00. That *is* an assignment to Const. However, "Const" itself is not an object, it's a constant. The name "constant" suggests it shouldn't change, which is why you get a warning when you assign something different to it. > Ok, I guess that goes back to the discussion above--the fact that it is > a different object doesn't (usually?) make a difference in a program I > might write. Here's a case where it does: # version 1 data = [] 10.times { |i| data[i] = "hello" } data[0] << "x" p data # version 2 str = "hello" data = [] 10.times { |i| data[i] = str } data[0] << "x" p data It does catch people out when they write, e.g. a = Array.new(10, []) when what they really want is a = Array.new(10) { [] } Try both these examples, printing out the object_id of each of the 10 elements of the array, to see how they are different. -- Posted via http://www.ruby-forum.com/.