From: Brian Candler Date: 2004-09-11T00:27:54+09:00 Subject: Variable scoping I've been away from this list for a while, so I don't know what the current thinking is behind the scoping rules for block-local variables, and whether they're likely to be changed. But I've just been bitten by this. Have a look at the following code, and see if you can see what's wrong with it just by inspection. It accepts TCP connections on a socket, and starts a server in a thread for each one. It's a nice pattern for TCP servers. ----------------------------------------------------------------------- require 'socket' module MyModule def run puts "Hello, world!" sleep 10 puts "Goodbye" # ... could do other stuff end end port = (ARGV[0] || 7000).to_i bind = (ARGV[1] || '0.0.0.0') server = TCPserver.new(bind, port) # For each connection, add our 'run' method to the I/O object and run it # in its own thread while (session = server.accept) session.extend MyModule Thread.new do begin session.run rescue Exception => e STDERR.puts "Caught exception: #{e}\n\t#{e.backtrace.join("\n\t")}" ensure session.close end end end ----------------------------------------------------------------------- To demonstrate the problem: run it in one window, and then in two further windows type "telnet localhost 7000" in each, less than 10 seconds apart. Watch the second one fail, and also see an exception reported by the server. After quite a bit of head-scratching, and boiling my server down to the simple code shown above, I managed to work out what was wrong and fix it. However, I wonder if the language could have helped me more here? "ruby -w" didn't spot any problem (although perhaps it would be hard for it to do so). I think this is a type of problem which unit testing is unlikely to find, unless you are specifically aware of it. Regards, Brian. v v v v v The fix: ----------------------------------------------------------------------- ... while (s = server.accept) s.extend MyModule Thread.new(s) do |session| begin ...