Decreasing range?

Hello everybody.

I just noticed a behavior I don't really get related to Range and
Enumerator.

if I write down something like (1..4).each { |i| p i } , this will print
1234
However, if I write (4..1).each { |i| p i }, nothing will be printed out
despite 4..1 is a valid range.

Can anyone explain me why this strange behavior is implemented as such,
and how can I circle that without the need to use the very ugly
1..4).each { |i| p (4-i) } ?

Thanks a lot for your answer,

Best regards

···

--
Posted via http://www.ruby-forum.com/.

4.downto(1) { |i| p i }

···

On Tue, Feb 1, 2011 at 12:51 AM, Stefano Grioni <stefano.grioni@epfl.ch>wrote:

Can anyone explain me why this strange behavior is implemented as such,
and how can I circle that without the need to use the very ugly
1..4).each { |i| p (4-i) } ?

Thank you both, I feel ashamed that I didn't think about "downto" ..
Concerning my more general question, do you have any clue about why
decreasing ranges behave the way they do?

Thank you

···

--
Posted via http://www.ruby-forum.com/.

This is certainly the most efficient variant. For the general case
there is Enumerable#reverse_each - at least from 1.8.7 on. Since it's
implemented in Range as well I guess this will be efficient, too.

Kind regards

robert

···

On Tue, Feb 1, 2011 at 8:01 AM, Josh Cheek <josh.cheek@gmail.com> wrote:

On Tue, Feb 1, 2011 at 12:51 AM, Stefano Grioni <stefano.grioni@epfl.ch>wrote:

Can anyone explain me why this strange behavior is implemented as such,
and how can I circle that without the need to use the very ugly
1..4).each { |i| p (4-i) } ?

4.downto(1) { |i| p i }

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Range#each calls the #succ method of the starting element to get the new one
and goes on like this until the next element is greater than the last. If
Range#each were written in ruby, I think it could be something like this (it's
just a guess, I didn't look at the actual code):

class Range
  def each
    current = @start
    while (current <=> @end) < 1
      yield current
      current = current.succ
    end
  end
end

In your case @start would be 4, while @end would be 1. Since 4 is greater than
1, the block is never called.

Stefano

···

On Tuesday 01 February 2011 17:43:44 Stefano Grioni wrote:

Thank you both, I feel ashamed that I didn't think about "downto" ..
Concerning my more general question, do you have any clue about why
decreasing ranges behave the way they do?

Thank you

Your use of <=> is perplexing, given that anything Comparable would
have a nicer operator for this purpose.

···

On Feb 1, 3:21 am, Stefano Crocco <stefano.cro...@alice.it> wrote:

class Range
def each
current = @start
while (current <=> @end) < 1
yield current
current = current.succ
end
end
end

--
-yossef

Yet, it's what Range uses. According to "The ruby programming language", for
an object to be used as a Range endpoint, it needs to have a <=>. It doesn't
need to include Comparable. Look at this:

class X
  def initialize n
    @n = n
  end
end

x1 = X.new(1)
x2 = X.new(5)

x1..x2
=> ArgumentError: bad value for range

class X
  def <=> other
    @n <=> other.instance_variable_get(:@n)
  end
end

x1..x2
=> #<X:0x8286ad8 @n=1>..#<X:0x8284ea4 @n=5>

As you see, you don't need to have a <, > or == method, just <=>.

Stefano

···

On Wednesday 02 February 2011 03:30:15 Yossef Mendelssohn wrote:

On Feb 1, 3:21 am, Stefano Crocco <stefano.cro...@alice.it> wrote:
> class Range
> def each
> current = @start
> while (current <=> @end) < 1
> yield current
> current = current.succ
> end
> end
> end

Your use of <=> is perplexing, given that anything Comparable would
have a nicer operator for this purpose.

--
-yossef

Wacky.

···

On Feb 1, 3:00 pm, Stefano Crocco <stefano.cro...@alice.it> wrote:

As you see, you don't need to have a <, > or == method, just <=>.

--
-yossef