in reply to Range Operators Question

The range operator has two different behaviors, depending on whether it is used in scalar or list context. Everything you've described above applies when the range operator is used in scalar context, whereas all your tests use it in list context..

perlop also describes the behavior of the range operator in list context, which is simply to return a list of values counting by one from the left operand to the right operand.

'z' .. 'a' is a special case. When the range operator is using magical autoincrement (like $var++), it stops when the string is greater than the right operand, or when the string is longer than the right operand. Thus, you'd get the same result from 'z' .. 'z' or 'z' .. '.'.

Replies are listed 'Best First'.
Re: Re: Range Operators Question
by dsb (Chaplain) on Jul 19, 2001 at 01:26 UTC
    Okay, now I see the difference between list and scalar context...I thought the whole section on the range operator referred to it in list context(and I tried to make sure that I carefully read the docs...DOH!). It is definitely more clear now.

    Still a bit confused though. After re-reading, I tried a few more examples. The goal of each is to print the numbers 5,6,7,8,9,10, one to a line.

    @arr = (1 .. 20); foreach $i ( 0 .. $#arr ) { if ( $i == (5 .. 10) ) { print "$i\n"; } } # output was "0\n" @arr = (1 .. 20); foreach $i ( 0 .. $#arr ) { if ( $i == 5 .. 10 ) { print "$i\n"; } } # output was 5-19, one integer to a line @arr = (1 .. 20); foreach $i ( 0 .. $#arr ) { if ( $i = (5 .. 10) ) { print "$i\n"; } } # no output - '$i = (5 .. 10)' never evaluated true
    Maybe I am misunderstanding how to use the operator is scalar context. The examples in the docs don't really help. Of all the examples listed, I thought the first was going to work. I'm really not understanding why it didn't.

    Thanks for your help to this point.

    Amel - f.k.a. - kel

      In scalar context, the range operator yields true or false. So comparing $i == (5..10) does not make sense. The code you want is:
      for $i (@arr) { if ($i==5 .. $i==10) { print "$i\n"; } }
      Or:
      for $i (@arr) { print "$i\n" if $i==5 .. $i==10; }

      --
      Mark Dominus
      Perl Paraphernalia

      Okay, your usage of the range operator in a scalar context isn't quite correct.

      I think what you're looking for is this:

      foreach $i ( 0 .. 19 ) { if ($i == 5 .. $i == 10) { print "$i\n"; } }
      You need to put the full comparison on each side of the range operator. Otherwise, you're doing something that's the equivalent of if ($string eq 'foo' || 'bar' || 'baz') {.

      There's one extra bit of info from perlop:

      If either operand of scalar ".." is a constant expression, that operand is implicitly compared to the $. variable, the current line number.
      So your snippets are doing implicit comparisons against $.:

      $i == (5 .. 10) compares $i to the result of the flip-flop, which flips when $. equals 5 and flops when $. equals 10.
      $i == 5 .. 10 flips when $i equals 5 and flops when $. equals 10.
      $i = (5 .. 10) assigns to $i the result of the flip-flop, which flips $. equals 5 and flops when $. equals 10.</code>

        Okay, just so I know I got it. I'm going to go back over the previous examples and see if I know why they don't work:
        @arr = (1 .. 20); foreach $i ( 0 .. $#arr ) { if ( $i == (5 .. 10) ) { print "$i\n"; } }
        That one doesn't work and only outputs 0 because of the way the condition is being read. Essentially $i is working out to be '0' or false, so the first iteration of the loop is the only one that will match. Why is the expression false is the tricky part. Well, it's because the operator is never "flipped" into true mode. Both operands are being compared to $. which is at 3 when the operator is being evaluated. The left operand is not 3 so it doesn't return true or flip the operator. Next...

        @arr = (1 .. 20); foreach $i ( 0 .. $#arr ) { if ( $i == 5 .. 10 ) { print "$i\n"; } }
        This code doesn't work right either. It outputs 5-20 one per line. Well, first of all, because of the precedence of the assignment operator(==), the expression is being read as '($i == 5) .. 10', so the operator is getting flipped true, but never flopped false because $. is, again, 3, which is definitley not 10. NEXT!!!

        @arr = (1 .. 20); foreach $i ( 0 .. $#arr ) { if ( $i = (5 .. 10) ) { print "$i\n"; } }
        This one was a shot in the dark to begin with, so I'm not that upset about it. Basically this one is similar to the first one in the way that the operator is never being flipped true. So $i is being assigned a '0' or false value, which evaluates the condition in the if block to false, so no print is ever executed.

        WOOHHOOOOOO!!! THanks for your help chipmunk, yer the best.

        Amel - f.k.a. - kel