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) } ?
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?
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) } ?
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?
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
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.