On 5/3/06, Rob Burrowes <rob / cs.auckland.ac.nz> wrote:
> Hmmm, it works if I bracket the range. Why is that?

I came to the same result as others. I also figured out why you were
getting that weird behavior when using the if statement. Let's take a
simple test: 3 in 2...5? In irb:

>> 2...5 === 3
ArgumentError: bad value for range

>> (2...5) === 3
=> true

Looks right, 5 === 3 was binding first, so in the first case we really
had 2...false (since 5 === 3 is false). To verify:

>> 2...false
ArgumentError: bad value for range

So why doesn't this code:

  [1,2,3,4,5,6,7,8,9,10].each do |x|
    puts x if 2...5 === x
  end

raise that exception? If I use select instead, it "works":

>> [1,2,3,4,5,6,7,8,9,10].select{ |x| 2...5 === x }
ArgumentError: bad value for range

The key is the binding again, let's look at that line with the condition again:

  puts x if 2...5 === x

This is the same as

  puts x if 2...(5 === x)

And since the default Object#===, which isn't overriden by the time we
reach Integer, returns false, we have:

  puts x if 2...false

regardless of x. Now, if 2...false meant a range, like it did other
times, the Range constructor would raise the expected exception.
*But*, this syntax appears as the condition of an if statement and the
special meaning of the ... comes into play. Since 2 never "matches" (I
think it uses the Object#=~ method here?), the switch is never turned
on.

Whew!

Jacob Fugal