Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid

Why doesn't the flip-flop operator work in all scalar contexts?

by siracusa (Friar)
on Oct 02, 2008 at 12:51 UTC ( #714999=perlquestion: print w/replies, xml ) Need Help??

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

Why doesn't the flip-flop operator work in all scalar contexts? It works fine when looping over a file handle:

while(<$fh>) { next if 1..1; # skip first line print; }

But it doesn't seem to work at all in other kinds of loops:

# intentionally not using range operator to avoid confusion for(1,2,3,4,5) { next if 1..1; # never returns true! print "$_\n"; }
my $i = 0; while(++$i <= 5) { next if 1..1; # never returns true! print "$i\n"; }

Both of those examples print the numbers 1 through 5, rather than skipping 1 and just printing 2 through 5.

The docs for perl 5.10 don't seem to indicate that it only works in the context of file handles. From perldoc perlop:

In scalar context, ".." returns a boolean value. The operator is bistable, like a flip-flop, and emulates the line-range (comma) operator of sed, awk, and various editors. Each ".." operator maintains its own boolean state. It is false as long as its left operand is false. Once the left operand is true, the range operator stays true until the right operand is true, AFTER which the range operator becomes false again. It doesn't become false till the next time the range operator is evaluated.

It just says "in scalar context," not "in scalar context if and only if you're looping over a file handle's records." Bad docs? Bad implementation? What am I missing?

Replies are listed 'Best First'.
Re: When doesn't the flip-flop operator work in all scalar contexts?
by merlyn (Sage) on Oct 02, 2008 at 12:54 UTC
    You need to keep reading that page. Two more paragraphs down it says:
    If either operand of scalar ".." is a constant expression, that operand is considered true if it is equal ("==") to the current input line number (the $. variable).
    Your examples with filereading change $., but your other examples don't. That's the difference.

      Sigh. Thanks, apparently my RTFM skills are weak this morning.

      ...although, what do they mean by "constant expression?" Is $x ever a constant expression? What kind of expression doesn't "evaluate to a constant?"

      my $x = 1; for(1,2,3,4,5) { next if $x..$x; # never returns true! print "$_\n"; }

        You just demonstrated the difference between a 'constant value' and a 'constant expression'.

        UPDATE: Arrrgh, again I fell into the trap of not reading thoroughly. Please ignore.

        UPUPDATE: After testing more thoroughly, it seems that when something like $x is used instead of 1, something happens that is not consistent with the docs:

        for(1,2,3,4,5) { $.= $_; next if 1..1; print "$_\n"; } #### prints as expected 2 3 4 5 my $x=1; for(1,2,3,4,5) { $.= $_; next if $x..$x; # never returns true! print "$_\n"; } #### prints nothing. Why??? It doesn't test against $. and it doesn't +just test the value $x my $x = 1; my $y = 0; for(1,2,3,4,5) { $.= $_; next if $x..$y; # never returns true! print "$_ "; } #### prints nothing as well. If the flip and the flop happened at the +same round it would have printed something

        Tried to run it with -Dx but that showed too much information. Wasn't there a debugging flag that shows just the compiled byte code?

        UPUPUPDATE: corrected a copying mistake and explained the wrong output some more
        while (<$fh>) { next if 1 .. 1; print "$_\n"; }


        while (<$fh>) { next if $.==1 .. $.==1; print "$_\n"; }

        so to do the same with a loop which counts over something other than $., you have specify it explicitly.

        for (1,2,3,4,5) { next if $_==1 .. $_==1; print "$_\n"; }

        what do they mean by "constant expression?"

        Short: Anything that Perl converts to a constant at compile-time.

        >perl -MO=Concise -e"print( 4 + 1 * 2 )" 6 <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v ->3 5 <@> print vK ->6 3 <0> pushmark s ->4 4 <$> const[IV 6] s ->5 <--- 4+1*2 -e syntax OK >perl -MO=Concise -e"print( 4 + $x * 2 )" a <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v ->3 9 <@> print vK ->a 3 <0> pushmark s ->4 8 <2> add[t3] sK/2 ->9 \ 4 <$> const[IV 4] s ->5 | 7 <2> multiply[t2] sK/2 ->8 | <--- 4+$x*2 - <1> ex-rv2sv sK/1 ->6 | 5 <#> gvsv[*x] s ->6 | 6 <$> const[IV 2] s ->7 /

        Long: A constant expression is known to Perl to always return the same result. It includes constants (including those created by constant), most operators operating on constants, some builtin functions, and functions with the () prototype whose body consist entirely of a constant expression (as per Constant Functions in perlsub).


        sub PI() { 4 * atan2(1, 1) } use constant SOMENUM => rand(4);

        Example of constant expressions:

        4 5+6*7 4 * atan2(1, 1) PI SOMENUM
        ...although, what do they mean by "constant expression?"

        Yeah, good question. Constant expression means whatever perl constant-folds at compile time. Numeric and string literals are constant, most simple operators (arithmetic and logic and things like that, but not including x) are constant-folded iff all their arguments are constants, and so are a few named builtins like uc, most other expressions aren't. There are some corner cases (like the comma operator) and even some version differences, so if you want to know for sure what's constant-folded and what isn't, you may need to dump the code with use O "Deparse"; or even use O "Concise";. If in doubt, just compare to $. explicitly if you want that semantics.

        There are at least two other cases where an expression being constant matters in how your perl code is interpretted, though one of these might be a bug: Twin-lines japh and Re^3: A cleaner way of scoping variables.

      So what happens if $. is incremented appropriately in the loop? Does it magically start working?

      Egads! It just worked!

      (Add you own caveats here)

      .sig : File not found.

Re: When doesn't the flip-flop operator work in all scalar contexts?
by Anonymous Monk on Oct 02, 2008 at 14:14 UTC

    Let me ask the question: what do you want?

    next, if 1 .. 3; will only call next when the left condition is true until the right condition is true.

    Written differently:

    while (<>) { next, if 2 .. 5; print; }

    Is sort of the same as:
    my $index = 0; my $skip = 0; while (<>) { $index++; if ($skip or $index == 2) { if ($index == 5) { $skip = 0; } next; } print; }

    If your code is looping over a sequence of numbers or if you are using another counter then you might be able to use: next if $_ == 2 .. $_ == 5;

      I'm not asking how to accomplish something. I'm just examining the dark corners of a particular operator, trying to determine if there are any bugs or "accidental features" lurking there.
      I would have sworn that next, if test wouldn't work, but it does. I can't understand why from the documentation of the comma operator, though—it seems like it should try to evaluate next, then if test (which is of course a syntax error), but that doesn't happen. Instead it seems to compile the same with or without the comma.

        My take on it: The 'if' always follows a simple statement so the parser takes 'next,' as statement. Depending on context (in this case void?) this will be either a comma operator or a list with a dangling comma. It seems the comma operator also throws away dangling commas like a list:

        > perl -e ' $d= (1,2); print "$d\n";' 2 > perl -e ' $d= (1,2,); print "$d\n";' 2

Log In?

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

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (4)
As of 2022-01-22 21:48 GMT
Find Nodes?
    Voting Booth?
    In 2022, my preferred method to securely store passwords is:

    Results (63 votes). Check out past polls.