2011-05-04

The bad and ugly: Ruby strings

Ruby is a language like Java, everything is reference to object. An assignment does not produce copy of the value, but the copy of the reference. So if you have an a object, and you say b=a then you will have a b object reference pointing to the same place as a.

The naive approach of a string is that if I say a='x12345y'; b=a; b.sub!('234','---'); will result in an a which's value is 'x12345y' and a b which's value is 'x1---5y'.

The Java guys invented the immutable pattern which means that after a string is created it cannot be modified. The sensation of modification comes from the construction of new strings from old ones, like s = s.concat("TEST") where s.concat("TEST") creates a new string which's reference may or may not be stored back at s itself.

But Ruby has weird behavior:

original = '|123|123|123|123|'
s = original
s['123']='TEST'
print(s,"\n")
s = original
s.sub!('123','TEST')
print(s,"\n")
will output
|TEST|123|123|123|
|TEST|TEST|123|123|
You do not know enough - they say, There are immutable objects in ruby too!. I just have to call the freeze method and the object will be immutable. Let's try it.

original = '|123|123|123|123|'
original.freeze # <--- NEW GUY
s = original
s['123']='TEST'
print(s,"\n")
s = original
s.sub!('123','TEST')
print(s,"\n")
will output
stringtest.rb:4:in `[]=': can't modify frozen string (TypeError)
        from stringtest.rb:4

That is just plain wonderful. We are still on the same place: nowhere. What would be the solution? Nothing sane is available. You have to use s = String.new(original) instead of simple assignment. This is a terrible looking pain in the ass solution.

Who the hell knows where was my string declared at the first time? Who knows what will be broken if I change a string I got from somewhere? Who will find the real problem for an error message like File not found: 'TEST'?

1 comment: