Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine

the '..' operator and decreasing values

by eXile (Priest)
on Mar 04, 2005 at 22:25 UTC ( #436782=perlquestion: print w/replies, xml ) Need Help??

eXile has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I just spent a few hours debugging because the construct
for my $i ( 10 .. 0 ) { # do something }
Doesn't do what I thought it should do, I expected it to count down, instead it returns an empty list . The perlop manpage describes this behaviour, but does anybody know why this behaviour was chozen?

Replies are listed 'Best First'.
Re: the '..' operator and decreasing values
by ikegami (Patriarch) on Mar 04, 2005 at 22:27 UTC

    .. always counts up. I don't know why, but this workaround will do the trick:

    for ( 0 .. 10 ) { my $i = 10 - $_; # do something }

        Let's hope the list isn't too long. for (0..x) is evaluated lazily, but I doubt that for (reverse x..0) is as well.

        On second thought, that would rarely matter.

        Does this create a list all at once so that it can reverse it as opposed ikegami's solution which creates only one value at a time? I ask because I honestly don't know.

        Update: Yarr...that's what I get for not refreshing.


        Feel the white light, the light within
        Be your own disciple, fan the sparks of will
        For all of us waiting, your kingdom will come

Re: the '..' operator and decreasing values
by Taulmarill (Deacon) on Mar 04, 2005 at 22:31 UTC
    simply reverse the list
    for my $i ( reverse ( 0 .. 10 ) ) { print "$i\n"; }
Re: the '..' operator and decreasing values
by cog (Parson) on Mar 04, 2005 at 23:27 UTC
    If you think about it, it makes sense; it's not "all values between X and Y", but rather "all values greater than X and lower than Y".

    If Y is smaller than X, of course, you get an empty list, but that can really be helpful, in some cases.

      Actually, its all values greater than OR EQUAL to X, and less than OR EQUAL to Y.
Re: the '..' operator and decreasing values
by eXile (Priest) on Mar 04, 2005 at 22:42 UTC
    thanks for the replies everybody, I already had a workaround (although that wasn't clear for the OP), and was just curious if anybody knows why this doesn't work as I expected, and why it returns an empty list. If I wanted to see if one value is bigger than the other, I could have simply compared them, I don't need '..' for that.
      The range operator uses the magic increment operator internally so that it can work on strings (i.e, 'a'..'zzz'). Since there is no corresponding magic decrement operator, it doesn't work in reverse. You could make the argument that for numeric endpoints, you don't need the increment/decrement to be magical, but this is the way it is...

      Well, contrariwise, it's useful in its current form if you want to be able to short-circuit out empty lists without having to do an explicit test. For (contrived, but based on a real-world memory) example:

      sub contrivance { my $min = shift; my $max = some_function(); for ($min .. $max) { print "I think that $_ is a valid possibility\n"; } }

      Contrived, as I said. But the point is that you can readily find a family of uses for the range operator where you'd want to return an empty list rather than counting backward if the RHS is less than the LHS, just as you can (and indeed, you have) for the opposite. Apparently, Larry thought my use case was more common than yours—lucky me, huh? :-)

      If God had meant us to fly, he would *never* have given us the railroads.
          --Michael Flanders

      this doesn't work as I expected
      The key element there being "I".

      Perl works as Larry expects. It's up to the rest of us to figure out what that means. (And for some of us to write about it and teach it.)

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

Re: the '..' operator and decreasing values
by phroggy (Monk) on Mar 05, 2005 at 00:25 UTC
    That's roughly equivalent to:
    for(my $i=10;$i<=0;$i++) { # do something }

    You can't use .. to count backwards, but try this:

    for my $i (reverse 0..10) { # do something }
    for $a(-2,12){for $b(0..7){$c=0;$_?hex substr( ef7fa1866706caeff02289402844,2*$_+$a,2)&2**(7-$b):0 and $c+=2**(7-$_)for(0..7);print chr $c;}}

      You might prefer

      for ( my $i = 10; $i--; ) { # do something }

      I regularly walk array indexes backwards, as you can shave a few cycles off of the standard

      for ( my $i = 0; $i < $array_size; $i++ ) { # whatever }

      logic that people love using in those languages that don't have a 'foreach' command.

Re: the '..' operator and decreasing values
by SolidState (Scribe) on Mar 06, 2005 at 16:57 UTC
    does anybody know why this behaviour was chozen?

    More important, I think, is the question "why doesn't use warnings; warn about this?
    I think this is the real question here. I too have been bitten by this behaviour and while it didn't cost me hours to debug, it did slow me down and was annoying to find. I don't know why use warnings; doesn't warn about this. I wish it did :-(
    After all, we already get messages such as "Useless use of a constant in void context at...". Why not something like "Useless use of an empty list in loop context at...", or something similiar.

    Just my 2 cents worth...
      Because that would be another useless warning. I write
      for ($x .. $y) { .. }
      quite often, knowing that it will not do anything if $y < $x.
      @a = 1 .. 3 # 3-element list @a = 1 .. 2 # 2-element list @a = 1 .. 1 # 1-element list @a = 1 .. 0 # 0-element list
      The latter to be a 2 element list would be very surprising (and would require a lot of extra code in my programs).
Re: the '..' operator and decreasing values
by sh1tn (Priest) on Mar 05, 2005 at 04:20 UTC
    do{ $_ = 100 unless$_;--$_; # do something } while $_

Re: the '..' operator and decreasing values
by deibyz (Hermit) on Mar 07, 2005 at 11:49 UTC
    I think that the cause of this behaviour is the Mathematical definition of interval.

    An interval [ a , b ] is defined as (free definition) "Every number greater than a and lesser than b" (definition). So, if a=2 and b=1, there's no number with such condition. That's a valid definition for every set with a ">" operator, so it could work with any set (class) with ">" defined and a valid "generator" (++) (This last statement is only theory, someone with time to test).

Re: the '..' operator and decreasing values
by TedPride (Priest) on Mar 05, 2005 at 19:22 UTC
Re: the '..' operator and decreasing values
by Woodchuck (Initiate) on Mar 05, 2005 at 21:28 UTC
    Wouldn't : foreach my $i (10 .. 0) { #Do something } do the trick instead??? -Woodchuck
      No, since "for" is simply an alias of "foreach", so that your code is exactly quivalent to the original poster's code.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://436782]
Approved by Tanktalus
Front-paged by Old_Gray_Bear
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (5)
As of 2023-06-07 15:15 GMT
Find Nodes?
    Voting Booth?
    How often do you go to conferences?

    Results (29 votes). Check out past polls.