Question

So, I believe this has something to do with the difference between arrays and lists, but I don't understand what's going on here. Can anyone explain how and why Perl treats an expression like (1..4) differently than (1, 2, 3, 4) and @{[1..4]}?

$ perl -de1

Loading DB routines from perl5db.pl version 1.31
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main::(-e:1): 1
  DB<1> x scalar (1,2,3,4)
0  4
  DB<2> x scalar (1..2,3,4)
0  4
  DB<3> x scalar (1,2..3,4)
0  4
  DB<4> x scalar (1,2,3..4)
0  ''
  DB<5> sub foo { (1..4) } # (the actual problem case, except 4 would be a variable)
  DB<6> x scalar foo()
0  ''
  DB<7> sub bar { @{[1..4]} } # (the workaround)
  DB<8> x scalar bar()
0  4
Was it helpful?

Solution

The "range operator" that produces a list just doesn't exist in scalar context -- the .. operator when used in scalar context is the "flip-flop operator" instead. The flip-flop operator starts off returning false, continues returning false until its left argument becomes true, then continues returning true until its right argument becomes true, after which it returns false and returns to its initial state. If all of that sounds pretty useless, consider

while (<>) {
  print if /BEGIN/ .. /END/;
}

The .. operator starts out false, so lines from the file aren't printed. But once the regex /BEGIN/ matches, the flip-flop becomes true, and all of the following lines will be printed, until the regex /END/ matches. From the line following "END", the flip-flop will be false again. So the effect is to only print lines between (and including, but you can control that) "BEGIN" and "END".

There's a little more magic with $. if either side is constant, but that's not really important. Read more on the flip-flop operator in perldoc perlop.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top