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 :)

Filed Under: | Tags:

Comments