Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister

!@#$ $#_

by MeowChow (Vicar)
on Mar 24, 2001 at 22:49 UTC ( #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?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://66880]
Approved by root
[Corion]: Meh. I think I have now the parts down that I want from a simple Javascript frontend for single-page- applications with a aPerl backend. But it seems that all Javascript templating modules either don't support two-way binding (which would be nice) or ...
[Corion]: ... don't support server-side precompilation (which means the client has to compile all templates to Javascript themselves), or are giant frameworks that expect to do everything (which is not what I want)
[Corion]: I feel that there is a talk somewhere in there, either about the structure and parts, or how I used several parts to get a complete whole.
[Corion]: Maybe I can still find something that is compatible with handlebars.js (which has JS precompilation) but allows for two-way data binding (which is great for the UI)

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (5)
As of 2017-03-30 07:47 GMT
Find Nodes?
    Voting Booth?
    Should Pluto Get Its Planethood Back?

    Results (355 votes). Check out past polls.