Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?

eval order of args to a sub

by otto (Beadle)
on May 30, 2007 at 18:10 UTC ( #618251=perlquestion: print w/replies, xml ) Need Help??

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


Is there a perl language spec on the order of evaluation of the arguments to a sub call?

As an example, suppose you have a sub that takes arguments, and in the call to the sub, the arguments are manipulated, causing a mutation to values. Hence the order of the argument evaluation just prior to the actual sub call will result in different values actually received by the sub.

Yes I can write a test program to determine an order, but unless that is part of the perl language spec, then it may not be the same for all versions of perl on various platforms.

This is a top-level posting of a question raised in nodes around 617201


Replies are listed 'Best First'.
Re: eval order of args to a sub
by ikegami (Pope) on May 30, 2007 at 19:56 UTC

    Perl evaluates the arguments from left to right (according to the associtivity of the list seperator).

    >perl -le"$i=3; print($i+0, ++$i, $i+0);" 344

    However, because Perl passes all arguments by reference, the order of operation sometimes *appears* unclear.

    >perl -le"$i=3; print($i, ++$i, $i);" 444

    The first snippet is similar to

    # $i=3; print($i+0, ++$i, $i+0); $i = 3; do { local @_; $anon0 = $i+0; alias $_[0] = $anon0; $i = $i+1; alias $_[1] = $i; $anon1 = $i+0; alias $_[2] = $anon1; &print };

    The second snippet is similar to

    # $i=3; print($i, ++$i, $i); $i = 3; do { local @_; $i; alias $_[0] = $i; $i = $i+1; alias $_[1] = $i; $i; alias $_[2] = $i; &print };

    Can you guess what the following prints?

    perl -le"$i=3; sub { $_[1]++; print @_ }->($i+0, ++$i, $i+0, $i);"
      That's very interesting. I could never have guessed that output before this thread. The creation of anonymous values (for lack of a better term) for some expressions makes me want to do some obfuscation...


        All scalar variables are really only references to SVs. (There's a similar relation between arrays and AVs, hashes and HVs, etc.) Sometimes Perl creates SVs to which no variable refers, and it's possible to create more than one variable that refers to the same SV.

        +------------+ references (1:1) +------------+ | Lexical or | -----------------------> | | | Package | | SV | | Scalar Var | referenced by (1:N) | | +------------+ <----------------------- +------------+

        The "anonymous values" are simply SVs.

      Can you guess what the following prints?
      perl -le"$i=3; sub { $_1++; print @_ }->($i+0, ++$i, $i+0, $i);"

      That's a sneaky one! I was completely wrong:
      syntax error at -e line 1, near "="

      PS: Just joking with you :)

      -=( Graq )=-

      thanks for that explanation, I experimented a bit with that behaviour and found this a fun example:
      perl -le'$i=3; print($i, $i++, $i);'
      perl -le'$i=3; print($i, $i+1, $i);'
      $ perl -e'$i=3; sub { $_[0]++; print @_ }->(++$i, $i+0);' 54 $ perl -e'$i=3; sub { $_[1]++; print @_ }->($i+0, ++$i);' 35
Re: eval order of args to a sub
by Tanktalus (Canon) on May 30, 2007 at 18:55 UTC

    I think the general rule of thumb is, "don't." As in, don't modify parameters to a function in the line that calls the function in such a way that could be confusing.

    foo($i++); # ok foo(++$i); # ok foo($i,$i++); # not ok foo($i++,$i); # not ok foo($i++,++$i); # WTF?
    If perl defined this, it would be one of very few languages that did so. And thus would still be confusing, IMO. It's not really that much extra work to avoid it. Use do if you have to:
    my $flubber = do { my @args; push @args, $i++; push @args, ++$i; foo(@args) }; # well defined: $_[1] == $_[0]+2

      Tanktalus++, best post in this thread: just "don't." And: avoid confusion.

      In that context I'd like to point at Quantum Weirdness and the Increment Operator, again, for a lengthy discussion of why modifying a variable more than one time via auto-{inc,dec}rement in the same statement is a very bad idea.


      _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                    /\_¯/(q    /
      ----------------------------  \__(m.====·.(_("always off the crowd"))."·
      ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: eval order of args to a sub
by dewey (Pilgrim) on May 30, 2007 at 18:48 UTC
    From perlsub:
    "...all functions are passed as parameters one single flat list of scalars, and all functions likewise return to their caller one single flat list of scalars."
    In other words, all subs have only one argument, a list value. Since the constructor for list values is the comma-separated list of values, the question becomes 'in what order are the arguments to the list-context comma operator evaluated?' Frustratingly, the documentation doesn't seem to say...

    My guess is that it's right to left in most implementations (due to the overloading of comma in scalar context) but that may not be dependable.

    Later: It is in fact defined as left to right! Thanks, ikegami.

    Later later: ummm, if this is crucial, please see discussion below. There is some disagreement.


        I think the moral of the story is "understand what you are passing to your functions".

        It appears that most ways that one might modify a variable in a function call will result in an alias to the variable being passed. Post-increment seems to be unique in that it creates an anonymous value.

        C:\>perl -e "sub foo{ print join qq/\n/, map { \$_ .' - ' . $_ } @_ } +foo($i=1,++$i,$i++,$i+1,$i+=1,$i); SCALAR(0x183059c) - 4 SCALAR(0x183059c) - 4 SCALAR(0x225f7c) - 2 SCALAR(0x18305fc) - 4 SCALAR(0x183059c) - 4 SCALAR(0x183059c) - 4

        TGI says moo

        Hmmm... I can't see where in Terms and List Operators (Leftward) the comma operator's order of evaluation is given... it mostly seems to concern term/parenthetical precedence. Am I missing something obvious?

        Also, I don't understand your `update' remark. Your code produces 1 1, as I would have expected... could you clarify?

      In other words, all subs have only one argument, a list value.

      I think this is misleading. There is a list of arguments, pushed onto the stack and popped off (or accessed directly). There may be a single value in the list of arguments, but to talk about a list as if it is a single argument is... misleading.

Re: eval order of args to a sub
by Trizor (Pilgrim) on May 30, 2007 at 18:55 UTC

    Arguments are passed to subs as a list. if you have foo($arg1,@moargs) it will recieve @_ = ($arg1,@moargs). In list context list elements are placed in the list in order. However prototypes can change the way the arguments are evaluated. foo (\@\%) causes perl to treat foo(@argar,%arghs) as foo(\@argar,\%arghs).

    This is all explained in perlsub which draws on information in perlfunc and perlop.

Re: eval order of args to a sub
by swampyankee (Parson) on May 30, 2007 at 19:22 UTC

    Evaluation order of arguments to a subroutine? One in a module, an intrinsic, or what?

    Perl passes arguments to a subroutine as a list (see perlsub); the order in which the arguments are processed is dependent on how the subroutine is written. So, unless you've got access to the routine's source (or the routine is properly documented), I would not assume any particular order (although it's probably left to right, as mentioned in Re^7: finding number of contiguous letters by blazar).

    Also, with my limited imagination, I can't conceive of a case where this matters and it's somewhere in the realm of what I've been taught as "good coding practice;" it reveals too much about the sub's internals.

    punctuation correction


    Any New York City or Connecticut area jobs? I'm currently unemployed.

    There are some enterprises in which a careful disorderliness is the true method.

    —Herman Melville
      I'm having trouble imagining a sub that controls the order of evaluation of its 'parameters'; that sort of control of execution feels like it requires macros. Could you give me an example? For instance, two subs first and second such that
      first(print('a'), print('b')) # prints 'ab' second(print('a'), print('b')) # prints 'ba'
      To me, this whole thing feels like a misunderstanding. Each sub receives one list value as an argument. We're not passing in expressions to be evaluated or anything like that.

Re: eval order of args to a sub
by andreas1234567 (Vicar) on May 31, 2007 at 09:33 UTC
    Slightly OT perhaps, but the freely available chapter 9 of Perl Best Pratices (PDF) recommends:
    Use a hash of named arguments for any subroutine that has more than three parameters. Named arguments should always be passed to a subroutine inside a single hash, like so:
    sub padded { my ($arg_ref) = @_; my $gap = $arg_ref->{cols} - length $arg_ref->{text}; my $left = $arg_ref->{centered} ? int($gap/2) : 0; my $right = $gap - $left; return $arg_ref->{filler} x $left . $arg_ref->{text} . $arg_ref->{filler} x $right; }
    # and then...
    for my $line (@lines) { $line = padded({ text=>$line, cols=>20, centered=>1, filler=>$SPAC +E }); }

Re: eval order of args to a sub
by polettix (Vicar) on May 31, 2007 at 16:46 UTC

Log In?

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

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (3)
As of 2021-01-23 14:18 GMT
Find Nodes?
    Voting Booth?