Dude, where's my String?
Posted by Rob, Tue May 22 20:10:00 UTC 2007
Ruby passes by reference, so I thought the following code would work just fine…
#!/usr/bin/ruby
class Filter
@@filters = []
def Filter.apply(string)
# We don't actually use the Filter instance,
# but don't worry about that.
@@filters.each { |f| yield string }
end
def initialize
@@filters << self
end
end
Filter.new()
Filter.new()
Filter.new()
Filter.new()
Filter.apply('foo') { |string|
string += 'h'
puts string
}
So, after the last iteration ‘foohhhh’ should be printed. But no. Hmm. But Ruby passes by reference… So… Eh?
I asked on #ruby.ie on freenode and Chris McGrath suggested I try << instead of +=, it worked. The deal is that string += 'h' translates to string = string + 'h', which is fine, obvious even. The problem is that the + operator causes a copy of the combined string to be returned, and string adjusted to point to the new instance of String. I would have expected this to change string in all scopes, but it only affected the local scope. Subsequent filters did not see the new string.
<< differs in that it is a method on the string instance itself which does an in-place change. This allows the other filters to see the change. Subtle, and a little surprising to me. Nice to know the fix, thanks Chris :)
