Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Scalar range operator again

by kejv2 (Novice)
on Jul 06, 2012 at 11:57 UTC ( #980243=perlquestion: print w/ replies, xml ) Need Help??
kejv2 has asked for the wisdom of the Perl Monks concerning the following question:

I have recently played little bit with this useful operator and came across its behaviour which is at least strange and confusing. Consider following one-liner:
perl -we'my @l = qw/ca qw/; for (@l) { print if /a/../c/ }'
According to documentation: "The right operand is not evaluated while the operator is in the "false" state, and the left operand is not evaluated while the operator is in the "true" state." So I would expect that the result of this code would be "caqw". I am assuming here that Perl processes each array element char by char "from left to right" and therefore doesn't evaluate /c/ operand, because it's in false state, and then goes to true state because it evaluates /a/ operand and stays so till the end.

The actual result is nevertheless only "ca" which I find really strange and almost wrong. What is your opinion of this Perls's behaviour? Don't you think it would be more logical it would print "caqw"?

Comment on Scalar range operator again
Download Code
Re: Scalar range operator again
by choroba (Abbot) on Jul 06, 2012 at 12:04 UTC
    Another important part of the documentation:
    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 can test the right operand and become false on the same evaluation it became true (as in awk), but it still returns true once. If you don't want it to test the right operand until the next evaluation, as in sed, just use three dots ("...") instead of two.
    Running your example with the three dot operator gives the "caqw" result.
Re: Scalar range operator again
by dsheroh (Parson) on Jul 06, 2012 at 12:13 UTC
    I am assuming here that Perl processes each array element char by char "from left to right"
    You assume incorrectly. The array is processed element-by-element, not character-by-character. The first element of the array is ca and the second element is qw.

    On the first pass through the loop, the flip-flop's state is false, so ca is tested against /a/, which matches, so it returns true, but it also tests against /c/ which resets it to false. From perldoc perlop:

    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 can test the right operand and become false on the same evaluation it became true (as in awk), but it still returns true once. If you don't want it to test the right operand until the next evaluation, as in sed, just use three dots ("...") instead of two. In all other regards, "..." behaves just like ".." does.
Re: Scalar range operator again
by Anonymous Monk on Jul 06, 2012 at 12:37 UTC
      Yes, I have read all those articles on the internet. But nowhere was described this counterintuitive behaviour. Of course, they point out that perl -we'my @l = qw/ac qw/; for (@l) { print if /a/../c/ }' would print ac and the same only with three dots prints acqw. This is completely understandable but not the case with @l = qw/ca qw/. Maybe it's really better to avoid such constructs as other monk has said.
        I have read all those articles on the internet. But nowhere was described this counterintuitive behaviour.
        Maybe it's just me, but perldoc's "It can test the right operand and become false on the same evaluation it became true (as in awk), but it still returns true once." seems to describe exactly this behavior. I'd even call it a clear description.
        they point out that perl -we'my @l = qw/ac qw/; for (@l) { print if /a/../c/ }' would print ac and the same only with three dots prints acqw. This is completely understandable but not the case with @l = qw/ca qw/.
        I don't get what you mean here. qw/ac qw/ and qw/ca qw/ are treated identically by the flip-flop operator:
        $ perl -E 'my @l = qw/ac qw/; for (@l) { say if /a/../c/ }' ac $ perl -E 'my @l = qw/ca qw/; for (@l) { say if /a/../c/ }' ca
Re: Scalar range operator again
by sundialsvc4 (Monsignor) on Jul 06, 2012 at 16:36 UTC

    And, in my humble opinion, the “flip-flop operator” is one of the total flops in the legacy design of Perl.   I studiously avoid using it, partly because I have been so badly bitten by code that did use it.   When I stumble upon it, I excise it.   Perl incorporates many clever and useful ideas, but this one is a turkey, because (as you see for yourself) you cannot “glance” at the code and immediately see at a glance what it will actually do.   I choose to instead to write a “boring, old, space-wasting” if-statement block that “obviously” describes what I want the computer to do.

    I really don’t want to start any sort of “flame war” here; it would be pointless to all.   Up/Down votes will more than suffice.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://980243]
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (5)
As of 2014-07-13 22:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    When choosing user names for websites, I prefer to use:








    Results (252 votes), past polls