I have encountered a weird situation while I’m writing a piece of code in Ruby. Here is the sample code extracting the essence of the problem I have faced. First, I tried to get the matching result with a line of code as follows.

p1 = /hello/
p2 = /world/

s = "hello, world"

if m1 = s.match(p1) || m2 = s.match(p2)
    puts "m1=#{m1}"
    puts "m2=#{m2}"
end

It shows:

m1=hello
m2=

Oops, I forgot that the logical operator || does the short-circuit evaluation. It makes m2 nil. What I wanted to do was checking both regular expressions are matching with the given string. Here is the correct one.

if m1 = s.match(p1) && m2 = s.match(p2)
    puts "m1=#{m1}"
    puts "m2=#{m2}"
end

But it shows:

m1=world
m2=world

Hmm, the result was unexpected. Why is m1 assigned by the outcome of p2 pattern? I expected that the result of the matching of p1 pattern is assigned to m1 and so forth for m2. Is the precedence of the operators correctly working?

According to the Ruby operator precedence, the logical operator && precedes the assignment operator =. Therefore, the evaluation order of the previous code should be same as:

if (m1 = s.match(p1)) && (m2 = s.match(p2))
    puts "m1=#{m1}"
    puts "m2=#{m2}"
end

Obviously, its outcome is expected.

m1=hello
m2=world

In reality, the evaluation looks like:

if m1 = (s.match(p1) && m2 = s.match(p2))
    puts "m1=#{m1}"
    puts "m2=#{m2}"
end

The logical operator follows the assignment to m2.

Since the result seems weird and I’m still not sure the mechanism behind this behavior, I posted one question in StackOverflow

I would very much appreciate it if you could find the answer to this problem. Thanks!

Reference