Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Regexp.last_match thread safe?

Tags:

ruby

This is the code that I'm looking at:

def method_missing(id, *args)
    return self.find(Regexp.last_match(1),  args[0]) if id.id2name =~ /find_by_(.+)/
    raise NoMethodError
end

What happens if I have multiple threads calling Regexp.last_match?

What happens if I have multiple threads calling the object with the method_missing method?

like image 201
Federico Avatar asked Jan 25 '12 14:01

Federico


2 Answers

The Ruby 1.9.2 platform docs state that calling Regexp.last_match is equivalent to reading the special $~ global variable.

From "The Ruby Programming Language", pg 318: "it is important to remember that $~ and the variables derived from it are all thread-local and method-local."

So Regexp.last_match is thread-safe. As for the other methods you are using in method_missing, I believe they are thread-safe as well. (If anybody knows differently, please edit this post.)

like image 78
Alex D Avatar answered Nov 16 '22 07:11

Alex D


TL;DR

Yes, Regexp special global variables are thread-safe because they aren't truly globals. Despite the fact that the variables have the word "global" in the name, the documentation says:

These global variables are thread-local and method-local variables.

Threads

You can prove this to yourself in the irb or pry REPL. For example, to test the variables' scope inside threads:

# Ensure $~ and friends are nil in case this isn't a fresh REPL.
''.match /foo/

# Make this variable available inside the thread block.
thread_match = nil

Thread.new do
  'foo'.match /(foo)/
  thread_match = "In thread: #{$1.inspect}"
end

[thread_match, "Global value: #{$1.inspect}"]
#=> ["In thread: \"foo\"", "Global value: nil"]

Methods

These special variables aren't even truly global when used within a method. Consider the following:

def foo
  'foo'.match /(foo)/
  p $1
end 

[foo, $1]
#=> ["foo", nil]

Conclusion

In other words, the Regexp special variables look like true globals because of the $ prefix, but do not persist outside the enclosing thread or method. To what extent that justifies calling them "globals" at all is something you'd have to take up with the language designers, or file a bug about if you feel strongly that it's misleading.

like image 38
Todd A. Jacobs Avatar answered Nov 16 '22 06:11

Todd A. Jacobs