Difference between .. and ... in boolean ranges

I’m a bit confused by some Ruby behavior I’m seeing with ranges. As I
understand it the difference between

0…5

and

0…5

is that the former includes the number 5 while the 2nd does not. That
seems to be the case, but one would expect the same type of behavior
in boolean context. For example, I’d think

0.upto(9) do |x|
if (x==3)…(x==5)
puts "In the range: #{x}"
else
puts "Not in the range: #{x}"
end
end

Would output:

Not in the range: 0
Not in the range: 1
Not in the range: 2
In the range: 3
In the range: 4
In the range: 5
Not in the range: 6
Not in the range: 7
Not in the range: 8
Not in the range: 9

while using the 3 dot form like this:

0.upto(9) do |x|
if (x==3)…(x==5)
puts "In the range: #{x}"
else
puts "Not in the range: #{x}"
end
end

Would output:

Not in the range: 0
Not in the range: 1
Not in the range: 2
In the range: 3
In the range: 4
Not in the range: 5
Not in the range: 6
Not in the range: 7
Not in the range: 8
Not in the range: 9

However, the 3 dot form doesn’t work as expected. It outputs the same
as the 2 dot form (which works as expected). What gives? This seems
unintuitive to me. Any thoughts?

Thanks,
Oliver

Oliver Dain wrote:

I’m a bit confused by some Ruby behavior I’m seeing with ranges. As I
understand it the difference between

0…5

and

0…5

is that the former includes the number 5 while the 2nd does not. That
seems to be the case, but one would expect the same type of behavior
in boolean context. For example, I’d think

0.upto(9) do |x|
if (x==3)…(x==5)
puts “In the range: #{x}”
else
puts “Not in the range: #{x}”
end
end

Would output:

Not in the range: 0
Not in the range: 1
Not in the range: 2
In the range: 3
In the range: 4
In the range: 5
Not in the range: 6
Not in the range: 7
Not in the range: 8
Not in the range: 9

while using the 3 dot form like this:

0.upto(9) do |x|
if (x==3)…(x==5)
puts “In the range: #{x}”
else
puts “Not in the range: #{x}”
end
end

Would output:

Not in the range: 0
Not in the range: 1
Not in the range: 2
In the range: 3
In the range: 4
Not in the range: 5
Not in the range: 6
Not in the range: 7
Not in the range: 8
Not in the range: 9

However, the 3 dot form doesn’t work as expected. It outputs the same
as the 2 dot form (which works as expected). What gives? This seems
unintuitive to me. Any thoughts?

Try: if (3…5) === x

Sean O'Dell

Oliver Dain odain2@nospam.mindspring.com wrote in message news:usP5b.8858$tw6.6413@newsread4.news.pas.earthlink.net

···

I’m a bit confused by some Ruby behavior I’m seeing with ranges. As I
understand it the difference between

0…5

and

0…5

is that the former includes the number 5 while the 2nd does not. That
seems to be the case, but one would expect the same type of behavior
in boolean context. For example, I’d think

0.upto(9) do |x|
if (x==3)…(x==5)
puts “In the range: #{x}”
else
puts “Not in the range: #{x}”
end
end

Would output:

Not in the range: 0
Not in the range: 1
Not in the range: 2
In the range: 3
In the range: 4
In the range: 5
Not in the range: 6
Not in the range: 7
Not in the range: 8
Not in the range: 9

while using the 3 dot form like this:

0.upto(9) do |x|
if (x==3)…(x==5)
puts “In the range: #{x}”
else
puts “Not in the range: #{x}”
end
end

Would output:

Not in the range: 0
Not in the range: 1
Not in the range: 2
In the range: 3
In the range: 4
Not in the range: 5
Not in the range: 6
Not in the range: 7
Not in the range: 8
Not in the range: 9

However, the 3 dot form doesn’t work as expected. It outputs the same
as the 2 dot form (which works as expected). What gives? This seems
unintuitive to me. Any thoughts?

Thanks,
Oliver


change: if (x==3)…(x==5) and (x==3)…(x==5)
to: if (3…5).include?(x) or (3…5).include?(x)
or: if (3…5).include? x or (3…5).include? x

for second case, you get output: “Not in the range: 5”

Jabari Zakiya

Hi!

I think i can answer.

When operator ‘…’ or ‘…’ is used in the condition expression,
it works like a flip-flop switch and returns true/false
(default is false).
The difference of the two is the timing of evaluation.
I think it is Perl-like.

a=[1,2,‘a’,3,4,5,6,‘b’,7,8,9]

a.each do |x|
if (x == ‘a’)…(x.is_a? String)
print x
end
end
#=> a

a.each do |x|
if (x == ‘a’)…(x.is_a? String)
print x
end
end
#=> a3456b

···

Oliver Dain odain2@nospam.mindspring.com wrote

I’m a bit confused by some Ruby behavior I’m seeing with ranges. As I
understand it the difference between

0…5

and

0…5

is that the former includes the number 5 while the 2nd does not. That
seems to be the case, but one would expect the same type of behavior
in boolean context. For example, I’d think

0.upto(9) do |x|
if (x==3)…(x==5)
puts “In the range: #{x}”
else
puts “Not in the range: #{x}”
end
end

Would output:

Not in the range: 0
Not in the range: 1
Not in the range: 2
In the range: 3
In the range: 4
In the range: 5
Not in the range: 6
Not in the range: 7
Not in the range: 8
Not in the range: 9

while using the 3 dot form like this:

0.upto(9) do |x|
if (x==3)…(x==5)
puts “In the range: #{x}”
else
puts “Not in the range: #{x}”
end
end

Would output:

Not in the range: 0
Not in the range: 1
Not in the range: 2
In the range: 3
In the range: 4
Not in the range: 5
Not in the range: 6
Not in the range: 7
Not in the range: 8
Not in the range: 9

However, the 3 dot form doesn’t work as expected. It outputs the same
as the 2 dot form (which works as expected). What gives? This seems
unintuitive to me. Any thoughts?

Thanks,
Oliver

Sean O’Dell wrote:

Try: if (3…5) === x

That’ll probably work… but I’m curious to know if Oliver Dain’s method
is supposed to work:

if (x==3)…(x==5)

and

if (x==3)…(x==5)

I’m surprised that they work at all, and I’m curious if the fact they
work in some way is a fluke, or if it was a conscious decision to try to
let them work like that. I’d expect a syntax error, but then again,
ranges as objects confuse me. :slight_smile:

Ben

jzakiya@mail.com (Jabari Zakiya) wrote in message news:a6fa4973.0309041930.46e4ab5a@posting.google.com

Oliver Dain odain2@nospam.mindspring.com wrote in message news:usP5b.8858$tw6.6413@newsread4.news.pas.earthlink.net
[snip]

0.upto(9) do |x|
if (x==3)…(x==5)
puts “In the range: #{x}”
else
puts “Not in the range: #{x}”
end
end

Would output:

Not in the range: 0
Not in the range: 1
Not in the range: 2
In the range: 3
In the range: 4
In the range: 5
Not in the range: 6
Not in the range: 7
Not in the range: 8
Not in the range: 9
[snip]

···

change: if (x==3)…(x==5) and (x==3)…(x==5)
to: if (3…5).include?(x) or (3…5).include?(x)
or: if (3…5).include? x or (3…5).include? x

for second case, you get output: “Not in the range: 5”

Jabari Zakiya


equivalent oneliners

0.upto(9) {|x| puts (((3…5).include?(x) ? “I” : “Not i”) + “n range: #{x}”)}
0.upto(9) {|x| print (((3…5).include?(x) ? “I” : “Not i”) + “n range: #{x}\n”)}
0.upto(9) {|x| print (((3…5).include?(x) ? “I” : “Not i”), “n range: #{x}\n”)}

Jabari Zakiya

Yes, but this is a single boolean not a boolean range. From what I
understand of the flipflop behaviour, the two dot case behaves like
this:

flag = true if (x==3)
if flag
body
end
flag = false if (x==5)

so by analogy, I’d expect the three dot case to be

flag = true if (x==3)
flag = false if (x==5)
if flag
body
end

martin

···

Sean O’Dell <sean@cseplsoafmt.com[remove_the_spam]> wrote:

Try: if (3…5) === x

Ben Giddings wrote:

Sean O’Dell wrote:

Try: if (3…5) === x

That’ll probably work… but I’m curious to know if Oliver Dain’s
method
is supposed to work:

if (x==3)…(x==5)

and

if (x==3)…(x==5)

I’m surprised that they work at all, and I’m curious if the fact
they work in some way is a fluke, or if it was a conscious decision
to try to
let them work like that. I’d expect a syntax error, but then again,
ranges as objects confuse me. :slight_smile:

Ben

Its my understanding that its not a fluke but a design decision. The
main reason for doing it, I think, is for regex’s. It allows you to
say things like:

while gets
print if /foo/…/bar/
end

e.g. print all lines between foo and bar. While Sean’s solution works
for numbers it doesn’t work for regular expressions and that was my
application of interest (I gave a numerical example because it was
easier to understand).

Martin DeMello wrote:

Try: if (3…5) === x

Yes, but this is a single boolean not a boolean range. From what I
understand of the flipflop behaviour, the two dot case behaves like
this:

flag = true if (x==3)
if flag
body
end
flag = false if (x==5)

so by analogy, I’d expect the three dot case to be

flag = true if (x==3)
flag = false if (x==5)
if flag
body
end

martin

I think you’ve got the 2 dot case right, but the 3 dot case is wrong.
Just to make the 2-dot and 3-dot cases look similar, here’s another
way to write the 2 dot code:

if flag == true
body
if (x==5) flag = false
else
if (x==3) flag = true
body
if (x==5) flag = false
end

Then the 3 dot case the code is:

if flag == true
body
if (x==5) flag = false
else
if (x==3) flag = true
body
end

The only difference is that if the an x matches both the beginning and
end condition your code doesn’t execute body for that x while mine
does:

For example:

0.upto(9) {|x|
if (x==3)…(x==3)
puts “#{x} is a match”
end
}

produces:

3 is a match
4 is a match
5 is a match
6 is a match
7 is a match
8 is a match
9 is a match

your pseudo-code wouldn’t have produced any output as x would have set
the flag true, but then immediately set it false and body would never
execute. What acutally happens is that when x is 3 it sets flag to
true. The end condition is not checked that iteration in the 3 dot
case. On the rest of the iterations the end condition is checked
but it is never true so all the rest of the values are output.

Just for reference, here’s what the 2 dot case does:

0.upto(9) {|x|
if (x==3)…(x==3)
puts “#{x} is a match”
end
}

produces:

3 is a match

···

Sean O’Dell <sean@cseplsoafmt.com[remove_the_spam]> wrote:

iI was basing my code on the following:

$ irb
irb(main):001:0> (3…3) === 3
(3…3) === 3
=> true
irb(main):002:0> (3…3) === 3
(3…3) === 3
=> false

martin

···

Oliver Dain odain2@nospam.mindspring.com wrote:

The only difference is that if the an x matches both the beginning and
end condition your code doesn’t execute body for that x while mine
does:

Martin DeMello wrote:

The only difference is that if the an x matches both the beginning
and end condition your code doesn’t execute body for that x while
mine does:

iI was basing my code on the following:

$ irb
irb(main):001:0> (3…3) === 3
(3…3) === 3
=> true
irb(main):002:0> (3…3) === 3
(3…3) === 3
=> false

martin

The above code is, I think, interpreted completely differently that
the “if (3==3)…(3==3)” code. Why? The latter is a boolean range
while the former first creates a range object and then applied
operator === to that. Things like ‘print if /foo/…/bar/’ operate
differently than other types of ranges because they’re boolean
ranges. For example you might think

ruby -ne ‘print if /foo/…/bar/’

would print all lines starting with the one that matches /foo/ up to,
but not including (since its a 3 dot range) the line that matches
/bar/. That would match the meaning of a “regular” range. But
that’s not how it works. Instead the above will match all lines
between /foo/ and /bar/ including the /bar/ line.

I think this is a really confusing distinction and I would prefer if
the boolean context range acted the same way as a regular range (e.g.
the 3 dot form means the end point isn’t included in the range,
etc.), but that isn’t how its done.

···

Oliver Dain odain2@nospam.mindspring.com wrote:

Sorry about the confusion - I was agreeing with your point about how it
should work.

martin

···

Oliver Dain odain2@nospam.mindspring.com wrote:

The above code is, I think, interpreted completely differently that
the “if (3==3)…(3==3)” code. Why? The latter is a boolean range
while the former first creates a range object and then applied
operator === to that. Things like ‘print if /foo/…/bar/’ operate
differently than other types of ranges because they’re boolean
ranges. For example you might think