Puzzeled by Range object

I was just writing an example for the “power of ruby” thread, using ranges.

I had two calls

b: (78…1).each {|y| print "#{y}, "}

The first worked as expected, it printed 1 to 78 to the screen.

However the second, simply printed nothing. Am I wrong to expect that a
range can work for both up and down?

(Using Ruby 1.6.6 windows installer, on Windows XP)

Rob

···

a: (1…78).each {|x| print "#{x}, "}

However the second, simply printed nothing. Am I wrong to expect that a
range can work for both up and down?

Range can work only up.

Except for Fixnum and Numeric, Range#each use #succ and it's difficult to
define the inverse of #succ for any type

Guy Decoux

I was just writing an example for the “power of ruby” thread, using ranges.

I had two calls

a: (1…78).each {|x| print "#{x}, "}
b: (78…1).each {|y| print "#{y}, "}

The first worked as expected, it printed 1 to 78 to the screen.

However the second, simply printed nothing. Am I wrong to expect that a
range can work for both up and down?

Yes.

(Using Ruby 1.6.6 windows installer, on Windows XP)

Rob

See:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/39324

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/8993

-Martin

···

On Thu, Aug 22, 2002 at 12:12:30AM +0900, Robert McGovern wrote:

However the second, simply printed nothing. Am I wrong to expect that a
range can work for both up and down?

Ranges works in upward direction only … and while I don’t know the
reason, I think it’s the right behaviour. Intuitive explanation (for
me) is:

(1…5) <=> “{ x | 1 < x && x < 5 }”

thus:

(5…1) <=> “{ x | 5 < x && x < 1 }”

W.

···


Wejn <lists+rubytalk(at)box.cz>
(svamberk.net’s Linux section, fi.muni.cz student, linuxfan)

    Bored?  Want hours of entertainment?         <<<
      Just set the initdefault to 6!             <<<

What about this?

batsman@kodos:~/src/rubylang$ cat myrange.rb

class Range
def each
if (first <=> last) == -1
# proceed in normal order
a = first
while ( a != last )
yield a
a = a.succ
end
yield last unless exclude_end?
else
# reverse!
a = last
a = a.succ if exclude_end?
while ( a != first )
yield a
a = a.succ
end
end
end
end

l = [ “(1…3).each { |x| puts x }”,
“(-3…1).each { |x| puts x }”,
“(1…3).each { |x| puts x }”,
“(-3…1).each { |x| puts x }” ]

l.each { |x| puts “Executing #{x}”; eval x }
batsman@kodos:~/src/rubylang$ ruby myrange.rb
Executing (1…3).each { |x| puts x }
1
2
3
Executing (-3…1).each { |x| puts x }
-3
-2
-1
0
1
Executing (1…3).each { |x| puts x }
1
2
Executing (-3…1).each { |x| puts x }
-3
-2
-1
0
batsman@kodos:~/src/rubylang$
Script terminado (Wed Aug 21 21:27:04 2002
)

It will surely break something, anybody cares to test it?

···

On Thu, Aug 22, 2002 at 01:03:07AM +0900, ts wrote:

However the second, simply printed nothing. Am I wrong to expect that a
range can work for both up and down?

Range can work only up.

Except for Fixnum and Numeric, Range#each use #succ and it’s difficult to
define the inverse of #succ for any type


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Because I don’t need to worry about finances I can ignore Microsoft
and take over the (computing) world from the grassroots.
– Linus Torvalds

Thu, 22 Aug 2002 04:27:06 +0900, Mauricio Fernández batsman.geo@yahoo.com pisze:

What about this?

batsman@kodos:~/src/rubylang$ cat myrange.rb

It breaks the property that (1…n) has n elements even for n==0.

The direction can’t be inferred from the order of ends. It must be
specified explicitly.

···


__("< Marcin Kowalczyk
__/ qrczak@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/

“Mauricio Fernández” wrote

What about this?

batsman@kodos:~/src/rubylang$ cat myrange.rb

class Range
def each
if (first <=> last) == -1

proceed in normal order

a = first
while ( a != last )

Better use * while ( a < last ) * or you
will get an inifinite loop if the range is
built with floats like (1 … 5.7)

However you might write come code such as

(start…10).each {|x| … }

I would expect such code to loop from start to 10 for a values of start
<= 10. For values greater than 10 I would not expect the code to run.

For my code to start ‘running backwards’ as it were would be very
counter intuative.

Then I’ll give another name for the new iterator with the other
semantic. Plus now “reverse” ranges are processed in order,
ie 1…-3 => 1 0 -1 -2 -3 instead of -3 -2 -1 0 1 as before.

Note that when doing (A…B).each2,
A.succ must be defined if A < B
B.succ must be defined if B >= A
That’s why (1…2.3).each2 and (1.1…-3).each2 both work
but not (1.1…3).each2 nor (1…-3.1).each2.

A <=> B (or the reverse) must be defined in both cases.

batsman@kodos:~/src/rubylang$ cat myrange.rb

class Range
def each2
if (first <=> last) == -1
# proceed in normal order
a = first
while (a <=> last) == -1
yield a
a = a.succ
end
yield last unless exclude_end? if (a <=> last) == 0
else
# reverse!
v =
a = last
a = a.succ if exclude_end?
while (a <=> first) == -1
v << a
a = a.succ
end
v << a if (a <=> first) == 0
v.reverse!
v.each { |x| yield x }
end
end
end

l = [ “(1…3).each2 { |x| print x, ’ ’ }”,
“(1…-3).each2 { |x| print x, ’ ’ }”,
“(1…3).each2 { |x| print x, ’ ’ }”,
“(1…-3).each2 { |x| print x, ’ ’ }”,
“(1…3.1).each2 { |x| print x, ’ ’ }”,
“(1…3.1).each2 { |x| print x, ’ ’ }”,
“(1.1…-3).each2 { |x| print x, ’ ’ }”,
“(1.1…-3).each2 { |x| print x, ’ ’ }”,
]

l.each { |x| print "Executing #{x}: "; eval x; puts }

batsman@kodos:~/src/rubylang$ ruby myrange.rb
Executing (1…3).each2 { |x| print x, ’ ’ }: 1 2 3
Executing (1…-3).each2 { |x| print x, ’ ’ }: 1 0 -1 -2 -3
Executing (1…3).each2 { |x| print x, ’ ’ }: 1 2
Executing (1…-3).each2 { |x| print x, ’ ’ }: 1 0 -1 -2
Executing (1…3.1).each2 { |x| print x, ’ ’ }: 1 2 3
Executing (1…3.1).each2 { |x| print x, ’ ’ }: 1 2 3
Executing (1.1…-3).each2 { |x| print x, ’ ’ }: 1 0 -1 -2 -3
Executing (1.1…-3).each2 { |x| print x, ’ ’ }: 1 0 -1 -2
batsman@kodos:~/src/rubylang$

···

On Thu, Aug 22, 2002 at 05:08:59PM +0900, Peter Hickman wrote:

However you might write come code such as

(start…10).each {|x| … }

I would expect such code to loop from start to 10 for a values of start
<= 10. For values greater than 10 I would not expect the code to run.

For my code to start ‘running backwards’ as it were would be very
counter intuative.


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

People disagree with me. I just ignore them.
– Linus Torvalds, regarding the use of C++ for the Linux kernel