For loops don't count down

Hello:

I just started learning Ruby. I like it’s OOness however I’ve run
across an unusual quirk with the “for loop” that. The “for loop” can
count up through a series of numbers, like so:

for number in (1…5)
puts number.to_s
end

which will output the digits 1 through 5. However, the “for loop” does
not appear to be able to count down when the range start and end is
reversed, like so:

for number in (5…1)
puts number.to_s
end

which outputs nothing. I realize that using “downto” can get me what I
want for down counting, like so:

5.downto(1) do |number|
puts number.to_s
end

but I’d like to use the for because it’s easier for me to see the start
and end of the block (especially when using syntax highlighting editors
like RDE).

Can anyone help be understand why the “for loop” can’t count down or if
there is an alternative “for loop” syntax that I’m missing.

Thank You,

Michael

On 2/19/07, Michael B. [email protected] wrote:

Hello:

I just started learning Ruby. I like it’s OOness however I’ve run
across an unusual quirk with the “for loop” that. The “for loop” can
count up through a series of numbers, like so:

for number in (1…5)
puts number.to_s
end

for number in [5, 4, 3, 2, 1]
puts number
end

(oh, note that puts calls .to_s already on its own :wink:

for number in (1…5).to_a.reverse
puts number
end

either is fine… however, it’s not looking very nice… i really
would like to have ranges from top to bottom… not in this
ruby-version available though.

anyway, how is the syntax-highlighting different for for…end vs
do…end?
and if you want matching highlighting, you can still do

5.downto(1) { |number|
puts number
}

that matches the braces, it’s the recommended syntax for oneliners
though.
like that:

5.downto(1){ |number| puts number }

please note also that for is just syntactic sugar to make the
transition easier for programmers of other languages, what it
essentially does is:

(1…5).to_a.reverse.each do |number|
puts number
end

hope i could help you with that a little
^ manveru

Michael

I never use ‘for’ loops in Ruby. So I can’t explain if or why not, etc.
But if you want to use ‘for’ loops, you could try something like this.

for number in (1…5).to_a.reverse
puts number.to_s
end

Harry

On Mon, 19 Feb 2007 07:28:36 +0100, Michael F.
[email protected] wrote:

what it essentially does is:

(1…5).to_a.reverse.each do |number|
puts number
end

Syntactically, I’d prefer “for number in 5…1” to that monstrous method
chain any day of the week.

David V.

On 2/19/07, Harry [email protected] wrote:

I never use ‘for’ loops in Ruby. So I can’t explain if or why not, etc.

“for x in xs” translates internally to “xs.each do |x|”, so the
underlying problem is that Range#each only counts upwards.

martin

Numeric#step counts down:

5.step(-1) do |i|
#stuff
end

Aur

On 2/19/07, David V. [email protected] wrote:

chain any day of the week.
Completely agree, for esthetically reasoning.
But in practice, I am afraid that there is no way to have this David.
As we need 5…1 to be an empty range, or am I blocked?

David V.

Robert

Hi,

In message “Re: For loops don’t count down”
on Mon, 19 Feb 2007 22:27:02 +0900, SonOfLilit
[email protected] writes:

|Numeric#step counts down:
|
|5.step(-1) do |i|
| #stuff
|end

5.downto(1) do |i|
end

          matz.

Michael F. wrote:

anyway, how is the syntax-highlighting different for for…end vs do…end?
and if you want matching highlighting, you can still do

5.downto(1) { |number|
puts number
}

> > (1..5).to_a.reverse.each do |number| > puts number > end > > hope i could help you with that a little > ^ manveru

Thank you for the reply. The syntax-highlighter highlights the “for”
and the “end” which are both on the left most edge of the block. I like
that because it saves me time scanning my code since I don’t have to
scan to the right to realize it’s a block.

I might use the “for number in (1…5).to_a.reverse” variation of the for
that Harry suggested below.

I just thought it was strange that the for couldn’t do the BASIC style
step -1 and the Ruby docs didn’t seem to discuss it that I could find.

Thank You!

That was already mentioned, but I wanted to show the moer general
solution since it was seeked.

Harry wrote:

I never use ‘for’ loops in Ruby. So I can’t explain if or why not, etc.
But if you want to use ‘for’ loops, you could try something like this.

for number in (1…5).to_a.reverse
puts number.to_s
end

Martin DeMello wrote:

On 2/19/07, Harry [email protected] wrote:

I never use ‘for’ loops in Ruby. So I can’t explain if or why not, etc.

“for x in xs” translates internally to “xs.each do |x|”, so the
underlying problem is that Range#each only counts upwards.

martin

Thank you Harry and Martin!

Harry, I’ll probably try your “to_a.reverse” suggestion for a while
(<-no pun intended :)).

Martin, thanks for the explanation! Maybe some day the Range#each will
be enhanced to look at the ends of the range and increment or decrement
accordingly.

Michael

Yukihiro M. wrote:

5.downto(1) do |i|
end

matz.

Hello Yukihiro:

Thank you for the reply. I tried the step, as shown above, and it
doesn’t work, it returns a 5, like so:

irb(main):013:0> 5.step(-1) do |i|
irb(main):014:0> puts i
irb(main):015:0> end
=> 5

However, adding the 1 parameter does work, like so:

irb(main):016:0> 5.step(1,-1) do |i|
irb(main):017:0> puts i
irb(main):018:0> end
5
4
3
2
1
=> 5

I’m glad that I’m forced to put in the 1 because I wouldn’t want it
counting down to zero without me realizing it.

However, coming from other languages (e.g. Delphi) I still prefer the
for…end syntax because of the more easily recognizable blocks it
creates, like so:

for

end

but in time I’m sure I’ll get used to seeing number / objects / sets /
ranges at the beginning of lines and won’t be so hung up on keywords
like “for”.

Maybe if the Range#each were smart enough to look at the start and end
value and count up or down accordingly that would fix things for the
(5…1) style syntax. I assume this wouldn’t just benefit the “for” but
would cause less gotcha’s wherever ranges were used.

BTW, thank you for creating such a wonderfully OO language. I looked at
Python and it seemed a little inconsistent at times, not to mention all
that , so I was impressed to find such an rich, clean and OO
oriented language like Ruby. I was equally impressed to see how much
forethought had gone into aspects like sets, iterators, etc. So, please
keep up the great work!

Michael

On Mon, 2007-02-19 at 22:38 +0900, Yukihiro M. wrote:

5.downto(1) do |i|
end

Is there a necessity for a range such as 5…0 to be empty? It would
otherwise be easy to make iteration work for such cases. This is a
simplified solution that doesn’t take into account #exclude_end?

class Range
def each
obj = first
if first <= last
while obj <= last
yield obj
obj = obj.succ
end
else
while first >= last
yield obj
obj = obj.pre
end
end
end
end

This would of course require that the objects in such a “reverse” range
respond to #pre, or whatever other name would be more suitable.

I’m basically asking if there is a reason why we shouldn’t expand the
functionality of Range#each, other than backwards compatibility (not
that that isn’t a big consideration.)

Cheers,
Daniel S.

“Martin DeMello” [email protected] writes:

On 2/19/07, Harry [email protected] wrote:

I never use ‘for’ loops in Ruby. So I can’t explain if or why not, etc.

“for x in xs” translates internally to “xs.each do |x|”, so the
underlying problem is that Range#each only counts upwards.

That’s not entirely true (there are differences in scope), but the
behavior of #each matters here, yes.

Ranges can’t be reversed in general, because there is no backward
equivalent to #succ.

Hi,

In message “Re: For loops don’t count down”
on Tue, 20 Feb 2007 02:45:27 +0900, Daniel S.
[email protected] writes:

|Is there a necessity for a range such as 5…0 to be empty?

5…1 is the easiest case, but what if “abz”…“abc” where we couldn’t
define reasonable String#pred. Just raise error?

I’d rather swap start and end for each operation, if empty iteration
is not wanted, until we have reverse iteration for generic case.

          matz.

In math classes, I’ve seen cases where it’s very comfortable that
Sigma (n = b to a) = 0 if b > a.
It was just nice to define something as an empty sum this way
(generalization of solutions).

It’s also more according to for(i = a; i < 5; i++) behavior, which is
something very useful. Perhaps we should have syntax for both types.
Or just Range#arrange (awul name) where (a…b).arrange would return
a…a if a<b .

Aur

On 2/19/07, Yukihiro M. [email protected] wrote:

Hi,

In message “Re: For loops don’t count down”
on Tue, 20 Feb 2007 02:45:27 +0900, Daniel S. [email protected] writes:

|Is there a necessity for a range such as 5…0 to be empty?

5…1 is the easiest case,
No it is not, how could we distinguish between a “reversed” range and
an “empty” range.
but what if “abz”…“abc” where we couldn’t
define reasonable String#pred. Just raise error?
With all due respect if we have a reasonable String#succ we can define
a reasonable String#pred.

I’d rather swap start and end for each operation, if empty iteration
is not wanted, until we have reverse iteration for generic case.

                                                    matz.

Cheers
Robert

Hi –

On Tue, 20 Feb 2007, Robert D. wrote:

No it is not, how could we distinguish between a “reversed” range and
an “empty” range.
but what if “abz”…“abc” where we couldn’t

define reasonable String#pred. Just raise error?
With all due respect if we have a reasonable String#succ we can define
a reasonable String#pred.

See the thread starting at ruby-talk 38910 for an earlier discussion
of this. It’s not easy, and it’s arbitrary and of questionable
usefulness. (I don’t think ranges need to be any more array-like than
they already are – possibly less.)

David

On 2/19/07, [email protected] [email protected] wrote:

See the thread starting at ruby-talk 38910 for an earlier discussion
of this. It’s not easy, and it’s arbitrary and of questionable
usefulness. (I don’t think ranges need to be any more array-like than
they already are – possibly less.)

I do not like the lack of symmetry it just feels not right.
I have mixed feelings about String#succ (can be convenient for sure
and very confusing too).
It is no good though to say String#pred will be the same mess, well
than let us remove String#succ too (unfortunately I guess that would
brake too much code.)
I’d like to have a look at the thread though (long time ago, or did I
miss it?) only that the N° is not really good enough for me to find
it.

Sorry if I am the nasty guy again :frowning:

Cheers
Robert

Hi –

On Tue, 20 Feb 2007, Robert D. wrote:

[email protected] writes:

See the thread starting at ruby-talk 38910 for an earlier discussion
of this. It’s not easy, and it’s arbitrary and of questionable
usefulness. (I don’t think ranges need to be any more array-like than
they already are – possibly less.)

I do not like the lack of symmetry it just feels not right.

You should adopt my Ruby slogan:

Ruby: the triumph of balance over symmetry.

:slight_smile:

David