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

I'm quite getting into the practical uses of the '..' operator, which seemed quite arcane and obscure to me in the past. However, if you want bracketed text, for example when trawling a log file, the flipflop does the business.
while (<>) { if (/BEGIN/ .. /END/) { do some stuff } }
But I am wondering if I can use this inside an iterator. I want it to retain its state information between successive calls to the iterator, as to which regexp it is looking for.

But, what's to stop someone from calling my code multiple times: multiple concurrent iterators. Will each flipflop keep track of its own state? What about if the multiple iterators are closures made from the same subroutine (hence same optree) - will this work?

Also, can I save and restore a given flipflop's state?

All help on this is most welcome.

--
I'm Not Just Another Perl Hacker

Replies are listed 'Best First'.
Re: State information for flipflop .. operator.
by ysth (Canon) on Aug 16, 2004 at 15:01 UTC
    You can keep track of it's state by storing its return value. If the last return value was false or =~/E/, it will look for the first regex on the next iteration; otherwise it will look for the second.

    A quick test:

    $ perl -we'sub makeit { my $i; sub { ++$i; ($i%6==1)..($i%6==3) } } $z = makeit(); $y = makeit(); print grep {&$y; &$z} "a".."r"' abcghimno
    shows that multiple closures made from the same anonymous sub have different states. The &$y call has no effect on &$z's return value.

    It is likely to be possible to save (and with 5.8.1, restore) a flipflop's state using the B module.

      A quick test ... shows that multiple closures made from the same anonymous sub have different states
      Nice one! That's what I wanted to hear.
      It is likely to be possible to save (and with 5.8.1, restore) a flipflop's state using the B module.
      I don't think my internals knowledge is up to it. A CPAN module that did this would be nice though :).

      In the mean time I am looking at preserving the input file position (with tell), together with the line counter and flipflop state using the return value from .. (in combination with $. when .. returns false). When I restore, I will need to short circuit the left operand if the flipflop state was on.

      Anyone see any issues with this?

      --
      I'm Not Just Another Perl Hacker

Re: State information for flipflop .. operator.
by pbeckingham (Parson) on Aug 16, 2004 at 14:07 UTC

    It's a strange, but nice operator isn't it?

    If you have looping that uses while (<>) then you have other reentrancy issues, and so you would need to rework that to use lexical file handles.

    The .. operator does actually return $., (shameless plug: check The Scalar Range Operator for a brief discussion on what the operator returns) so you do stand a chance of being able to save and restore state yourself, but would need to skip already-processed input yourself by reading up until $.. I don't think your task is an easy one.



    pbeckingham - typist, perishable vertebrate.

      Maybe I'm misunderstanding you and maybe I'm wrong, but as far as I know .. doesn't return $. -- for example:

      my @letters = qw(a b c d e); #'a'..'e' also works, #but I didn't want to add #a red herring ;-) print ' $_ | $r | $.'."\n"; for (@letters) { if(my $r = /a/../e/) { printf "%4s |%4s |%4s\n", $_, $r, $.; } $.++; # ok, this is silly # but I'm making a point ;-) }

      The output is the following:

      $_ | $r | $. a | 1 | b | 2 | 1 c | 3 | 2 d | 4 | 3 e | 5E0 | 4

      You're thread is pretty infomative, perhaps you meant something other than you wrote?

      ---- The super-user prompt is set to # to remind users of its awesome power.

        Well, no, I meant what I said. $. while reading a file is different from the zero-based array index. Here is your code now reading from __DATA__:

        #! /usr/bin/perl -w use strict; my @letters = qw(a b c d e); #'a'..'e' also works, #but I didn't want to add #a red herring ;-) print ' $_ | $r | $.'."\n"; for (@letters) { if(my $r = /a/../e/) { printf "%4s |%4s |%4s\n", $_, $r, $.; } $.++; # ok, this is silly # but I'm making a point ;-) } print "\n", ' $_ | $r | $.'."\n"; while (<DATA>) { chomp; if(my $r = /a/../e/) { printf "%4s |%4s |%4s\n", $_, $r, $.; } } __DATA__ a b c d e
        And the output is (hey - use strict found an error):
        $_ | $r | $. Use of uninitialized value in printf at ./r2.pl line 12. a | 1 | b | 2 | 1 c | 3 | 2 d | 4 | 3 e | 5E0 | 4 $_ | $r | $. a | 1 | 1 b | 2 | 2 c | 3 | 3 d | 4 | 4 e | 5E0 | 5



        pbeckingham - typist, perishable vertebrate.