[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Difference between .. and ... in boolean ranges

Oliver Dain

9/4/2003 10:59:00 PM

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
11 Answers

Sean O'Dell

9/4/2003 11:49:00 PM

0

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

Ben Giddings

9/5/2003 12:57:00 AM

0

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. :)

Ben


Oliver Dain

9/5/2003 1:30:00 AM

0

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. :)
>
> 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).

jzakiya

9/5/2003 3:30:00 AM

0

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

Shin Nishiyama

9/5/2003 4:28:00 AM

0

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
>
>
>

jzakiya

9/5/2003 4:19:00 PM

0

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

Martin DeMello

9/6/2003 9:49:00 AM

0

Sean O''Dell <sean@cseplsoafmt.com[remove_the_spam]> 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

Oliver Dain

9/6/2003 2:58:00 PM

0

Martin DeMello wrote:

> Sean O''Dell <sean@cseplsoafmt.com[remove_the_spam]> 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




Martin DeMello

9/6/2003 3:53:00 PM

0

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:

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

9/6/2003 4:44:00 PM

0

Martin DeMello wrote:

> 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:
>
> 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.