Unexpected behavior of range.each (Newbie extreme)

with r=(5…9), r.each{|num| print num,"\n"} behaves as expected.

However if i set r=(9…5) the same method does not behave as though it
were taking “each” element of the range. It just terminates. Not only
that but r.include?(7) is false???

Is this a bug or was it done on purpose for some reason? Are range
specifications only allowed to be “low to high” if so, why? Also if
so, then why no error message and why does r = (9…5)?

Thanks in advance!
joe

On Mar 11, 2006, at 6:53 PM, Tim H. wrote:

It was done on purpose. Ranges want to be able to iterate from
beginning to end using the .succ method on the objects that the
range is constructed from. That’s not possible for (9…5). Also,
the definition for .include? is range.start <= val <= range.end.
Not true for (9…5).

There have been several threads over the last few months
regarding the peculiarities of Ranges. The semantics seem
a bit confused. Sometimes ranges behave like generated sequences
of objects, sometimes they behave like intervals, and sometimes
they just behave like a coordinate pair. The behavior also depends
quite a bit on the objects used to construct the range.

They are quite convenient in any number of situations but they
have some rough edges. Is it worth trying to craft an RCR that
smooths things out a bit?

Gary W.

Joe P. wrote:

Thanks in advance!
joe

It was done on purpose. Ranges want to be able to iterate from beginning
to end using the .succ method on the objects that the range is
constructed from. That’s not possible for (9…5). Also, the definition
for .include? is range.start <= val <= range.end. Not true for (9…5).

Timothy H. wrote:

Joe P. wrote:

Thanks in advance!
joe

It was done on purpose. Ranges want to be able to iterate from beginning
to end using the .succ method on the objects that the range is
constructed from. That’s not possible for (9…5). Also, the definition
for .include? is range.start <= val <= range.end. Not true for (9…5).

seems like an odd definition of “include” (and “each”) and inconsistent
with the behavior for arrays. Also, if (9…5) is not a valid range
specification why no error message?
It seems to me that the definition of include (and each) for a range
could be made a bit more tollerant of direction by making it conditional
on the order of the endpoints. Ahh…Well… guess I ought to stop
complaining and just go back to learning the language :slight_smile:

Thanks for the explanation!
joe

Joe P. [email protected] writes:

seems like an odd definition of “include” (and “each”) and inconsistent
with the behavior for arrays. Also, if (9…5) is not a valid range
specification why no error message?

You can’t error on construction simply because end < start. Consider:

str[2…-1]

It seems to me that the definition of include (and each) for a range
could be made a bit more tollerant of direction by making it conditional
on the order of the endpoints. Ahh…Well… guess I ought to stop
complaining and just go back to learning the language :slight_smile:

You could make Ranges go backwards, but that changes the soul of the
ruby Range. (Confusion and code breakage everywhere.) I think having
backwards ranges do nothing can also have its uses, though I can’t
conjure up a convincing one on the spot.

Hey Joe (Whatcha doin’ with that gun in your hand? – a little Jimi
Hendrix for you)

Someone might have a better answer than me, but I’ll give it a shot.

The answer to your question is yes, this is intended behavior. Let’s
look at the Ruby documentation for Range#each:

“Iterates over the elements rng, passing each in turn to the block. You
can only iterate if the start object of the range supports the succ
method (which means that you can’t iterate over ranges of Float
objects).”, class Range - RDoc Documentation

Basically, when r = (9…5), you’re first saying: 9#succ, which returns
10. 10’s outside of your Range which tells #each to stop.

So, yes: “low to high”. I’m not sure, however, why there’s no error
message.

I hope you found this helpful.

James