From: Martin DeMello Date: 2012-12-23T12:38:14+09:00 Subject: Re: POLS and string-handling On Sat, Dec 22, 2012 at 3:15 PM, Paul Magnussen wrote: > # b) String > > myString3 = "Fred Nerk" > myString4 = myString3 > > myString4[0,4] = "Bert" > > => myString3 = "Bert Nerk" > => myString4 = "Bert Nerk" > > myString3 has been "corrupted", presumably because setting myString4 to > it actually set myString4's pointer, not its value, in the standard OO > fashion. There's a subtle point here: > myString3 = "Fred Nerk" = is a built in piece of syntax to bind a variable to an object. Variables are not themselves objects, they are transparent references to objects. The only time a variable cannot be transparently replaced by the object it refers to is when it's on the left hand side of an equal sign. So here, "Fred Nerk" uses the string literal to create the string object # [that is, an object with type String, object_id 0x01234567 and value "Fred Nerk"] on the heap, and binds the variable myString3 to it. > myString4 = myString3 Here, myString3 is transparently replaced by the object it refers to, #, and myString4 is bound to the same object > myString4[0,4] = "Bert" This is the subtle bit. Despite the syntactic sugar, this is *not* an = sign. There is no variable binding = involved here, it is just ruby syntax sugar that gets rewritten to myString.[]=(0, 4, "Bert"). That is, it calls the "[]=" method on the string object, passing it values (0, 4, "Bert"). Again, since myString4 is not on the left hand side of an =, it gets transparently replaced by #, which then gets sent the message []= with arguments (0, 4, "Bert"), and obligingly updates its value. So our object is now # (note that the object hasn't changed, just its value). > => myString3 = "Bert Nerk" > => myString4 = "Bert Nerk" Again, these are both transparently replaced by the object they refer to, now # > But > > # c) String literal > > myString1 = "Fred Bloggs" Creates # on the heap, binds myString1 to it. > myString2 = myString1 Binds myString2 to # > myString2[0,4] = "Bert" Sends []=, (0, 4, "Bert") to #, which updates itself to # > puts "Fred Bloggs = " + "Fred Bloggs" Creates two *new* string object, # and passes the second one as an argument to the + method of the first, which returns yet another string object, # which it passes to "puts" which prints it out. > puts "myString2 = " + myString2 Creates *one* new string object, # (the transparent replacement for myString2) as an argument. This creates yet another string object, #, which gets passed to puts and printed out. [Note that all the string objects that got created but never had variables bound to them are temporary objects that the garbage collector will take care of at some point] > So how to get around this? The following appears to do it: > > # f) String constant 3 > > MyString8 = "Fred Shufflebotham" > myString9 = MyString8.clone Clone creates a new string object, and sets its value equal to that of the first one. = then binds myString9 to this new object. > myString9[0,4] = "Bert" the []=, 0, 4, "Bert" message is getting sent to the new object > => MyString8 = "Fred Shufflebotham" myString8 is still bound to the first object, which never got sent a message. > => myString9 = "Bert Shufflebotham" myString9 is still bound to the new object, which *did* get sent the []= message and updated its value > but doesn't it cause a memory leak? No, the garbage collector takes care of it. martin