Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

!@#$ $#_

by MeowChow (Vicar)
on Mar 24, 2001 at 22:49 UTC ( [id://66880]=perlquestion: print w/replies, xml ) Need Help??

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

In attempting to formulate another reply to this little game of golf, I've hit upon some rather peculiar behaviour in list expression evaluation order. Consider the following recursive code:
sub li { shift; @_ ? (scalar @_, &li) : (); } print li qw(a b c d e f g); # prints 654321
So far so good... now substitute $#_ + 1 for scalar @_:
sub li { shift; @_ ? ($#_ + 1, &li) : (); } print li qw(a b c d e f g); # prints 654321
Que bueno! Moving on, lets remove the "+1" ...
sub li { shift; @_ ? ($#_, &li) : (); } print li qw(a b c d e f g); # prints -1-1-1-1-1-1
What is this? Apparently, $#_ is now evaluated after the recursive call. To my eyes, this is a rather unexpected result, especially when you consider how the comma operator behaves in a scalar context, and my first two examples. This phenomenon affects globals as well:
use vars '$x'; sub li { $x = shift; @_ ? ($x, &li) : (); } print li qw(a b c d e f g); # prints gggggg
Update: remarkably, I've just determined that this behaviour is tied to the way in which the subroutine call is performed: if the calls above are switched from &li to li(@_), the order of evaluation goes back to normal. How wierd!
Update2: actually, the above only works for the $#_, but not the globals. Stranger and stranger...

Replies are listed 'Best First'.
Re: !@#$ $#_
by chromatic (Archbishop) on Mar 24, 2001 at 23:23 UTC
    There's a thread on p5p that has to do with Precedence. Just like in C, the order of evaluation is not strictly determined.

    The original thread starts here, where our own japhy says "It hurts when I stick a fork in my eye!"

    Seriously, it's a combination of recursion and modifying a global (@_). If you copy the arguments into a lexical array in li(), you'll get better results.

    Update: chromatic resolves to be more specific about his terminology.

      Yeppers, I suppose the following snippet fully illustrates the issue, without employing side-effect operators:
      my $i = 0; sub foo { $i = $i + 1 } print ($i, ${\$i}, foo(), $i + 0, foo(), foo(), foo(), $i); ### prints: 44112344
      It looks as if any complex sub-expressions /subroutine calls are evaluated in order, and variables/references are evaluated last.

      Seems rather un-perlish, but at least subroutine calls are done in-order.

        Says MeowChow:
        It looks as if any complex sub-expressions /subroutine calls are evaluated in order, and variables/references are evaluated last.
        That's very astute of you. It's not exactly what's going on, but it's very close. For simple variables, Perl pushes what is effectively a reference onto the stack. But for complex ecpressions, Perl must construct the new value and push a reference to that instead. So if $i = 2, then $i in the list pushes a reference to $i itself, but $i + 0 copies $i and pushes a reference to the copy of the 2. If you later change $i, the first 2 changes but the second one doesn't.

        Your original example works the same way.

        This could be considered a bug. It has come up on p5p before, but I don't remember what the outcome of the discussion was.

        Contrary to what chromatic said, it is not a precedence issue. Precedence only affects parsing, not execution.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (2)
As of 2024-03-19 07:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found