Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Short Circuit Operator and Hash Assignment

by periapt (Hermit)
on Mar 17, 2004 at 16:25 UTC ( [id://337386]=perlquestion: print w/replies, xml ) Need Help??

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

While considering a previous perl question, I was reminded of an odd occurance for a bit of code. The line  $idx{$val} ||= 1 && push @num, $val; in the below snippet will store the selection count of $val into $idx{$val} rather than the value 1 as expected. For example, if the number in $val is the fourth number selected from the random sequence , this code will store the value 4 in $idx{$val}. I'm at a loss as to why this would happen. Interestingly, if the same value occurs in the random sequence a second time (ie the $idx{$val} is already defined), the code will not change the count in $idx{val}. Any ideas?
my %idx = (); my $val = 0; my @num = (); my $nrndded = 3; my $ulmt = 10; while(scalar keys %idx < $nrneeded){ $val = int(rand($ulmt-1)+1); # map range to (1..ulmt) $idx{$val} ||= 1 && push @num, $val; }

Replies are listed 'Best First'.
Re: Short Circuit Operator and Hash Assignment
by hardburn (Abbot) on Mar 17, 2004 at 16:29 UTC

    After running that line through B::Deparse:

    $idx{$val} ||= push(@num, $val);

    The 1 && part is being optimized out of the statement.

    Note, too, that the exact operator precedance in Perl5 is poorly defined, and there are many edge cases that don't work out quite as you'd expect.

    ----
    : () { :|:& };:

    Note: All code is untested, unless otherwise stated

      Note, too, that the exact operator precedance in Perl5 is poorly defined, and there are many edge cases that don't work out quite as you'd expect.
      Gah, you make it sound as though Perl rolls dice to determine operator precedence. The exact operator precedence in Perl is quite well-defined, and there are no random number generators involved. But people fail to understand it in two different ways. First, they simply don't bother to learn the precedence table, which was the problem in this case (and is the usual problem). I think people get lazy because operator precedence usually DWIMs, so they figure it will always DWIM, and then are surprised when it doesn't.

      The other way that people fail to understand operator precedence is that they don't know when it doesn't apply. It's important to understand that a yacc grammar uses operator precedence only to break ties between ambiguous rules in the grammar. If the grammar specifies that something can only be parsed in a particular way, operator precedence never comes into it. You may think that the $ on the front of a variable is a unary operator, but it's not, because what comes after it is not allowed to be a general expression. The grammar restricts the following item to be an identifier, a simple scalar variable, or a block, and these are all recognized by the grammar without recourse to operator precedence. If you try to treat $ as a unary operator, you will certainly be surprised when it doesn't work that way. But it's not an "edge case" of operator precedence. It's simply getting nowhere near the operator precedence table in the first place.

        I was thinking of "edge cases" where there is a tie in the precedence table, such as in Auto-increment frenzy. Which seems to be a recurring theme on the Fun With Perl mailing list.

        ----
        : () { :|:& };:

        Note: All code is untested, unless otherwise stated

      The 1 && part is being optimized out of the statement.
      this seems a rather dangerous and naive optimization to me, given that also this:
      $x = 1 && $y = 2; $x = 0 || $y = 2;
      gets "optimized" as:
      $x = $y = 2; $x = $y = 2;
      perhaps the p5p people should do something about it.

      cheers,
      Aldo

      King of Laziness, Wizard of Impatience, Lord of Hubris

        this seems a rather dangerous and naive optimization to me

        The optimization is a red herring; it's not changing the result in any way. If the left operand of the && operator is true in boolean context, then it returns the value of its right operand, whatever that may be. Expecting it to return the left operand is wrong. (What you really were expecting is a different parse, based on different operator precedence. (See my other post downthread.))


        ;$;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$;[-1]->();print

        You're hitting an edge case. The optimization had a different situation in mind:

        if( 1 && foo() ) { . . . } elsif( 0 || bar() ) { . . . }

        This optimization is hardly unique to Perl. I believe both C and Java compilers will optimize away constants in exactly the same way.

        ----
        : () { :|:& };:

        Note: All code is untested, unless otherwise stated

Re: Short Circuit Operator and Hash Assignment
by dragonchild (Archbishop) on Mar 17, 2004 at 17:56 UTC
    From the Camel (3rd ed.) pp. 87-88, you'll see that && has a higher precendence than =. So, your statement actually looks like:
    $idx{$val} ||= (1 && push(@num, $val));
    Then, and only then, does the optimizer deal with the '1 &&' part. This is in contrast to using 'and' instead of '&&', which binds looser than = (and its sibling ||=). Try it out!

    ------
    We are the carpenters and bricklayers of the Information Age.

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: Short Circuit Operator and Hash Assignment
by jonadab (Parson) on Mar 17, 2004 at 18:10 UTC

    Your code is hitting the difference between && and and. The former is for logically anding two simple values together within a larger expression; the latter, spelled-out, low-precedence and is for anding together larger expressions, which is what you're doing here. You should be spelling out and in this case. Or, when in doubt, parenthesize.

    It may be noted that in practice and is a much more common and useful operator than &&, though both have their uses.

    They both short-circuit in the same way, and I suspect that both might also optimize the same way in a parenthesized case, though what gets optimized is really an internals issue that does not make a lot of difference at the language level. (In your code, if the 1 && were not optimized away, the result would still be the same and would still not be what you want. The optimization is just an implementation detail.)

    There are languages that are largely immune to this sort of issue, due to not having complex precedence tables. Most lisp-based languages fall into this category: Common Lisp, Scheme, elisp, and so on. But to work with those languages, you really NEED an editor that does paren matching or automatic indentation -- preferably both.


    ;$;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$;[-1]->();print
Re: Short Circuit Operator and Hash Assignment
by Not_a_Number (Prior) on Mar 17, 2004 at 20:06 UTC

    Just a side comment:

    $val = int(rand($ulmt-1)+1);  # map range to (1..ulmt)

    This does not do what you claim in your comment. Either change your comment to:

    # map range to (1..(ulmt-1))

    or change your code to:

    $val = int(rand($ulmt)+1);

    dave

Re: Short Circuit Operator and Hash Assignment
by periapt (Hermit) on Mar 17, 2004 at 20:07 UTC
    There you have it. Precedence. Seems a lot less interesting now. I see that the statement is assigning the array length to $idx{$val}. That works actually since the only purpose of the assignment is to define the key in the hash. Kind of an unnecessary evaluation though. Oh well, nothing like getting caught with your parenthesis down.

    Thanks for the input.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://337386]
Approved by Limbic~Region
Front-paged by broquaint
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (3)
As of 2024-04-25 22:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found