Re: order of arguments evaluated
by Joost (Canon) on May 17, 2005 at 06:28 UTC
|
#!/usr/local/bin/perl -w
use strict;
my $i = 1;
$i = $i++ + $i;
print $i;
| [reply] [d/l] |
Re: order of arguments evaluated
by Zaxo (Archbishop) on May 17, 2005 at 06:28 UTC
|
The increment operator is evaluated before the comma operator is, I believe due to higher precedence. It is unwise to mix increment/decrement ops in a statement with other expressions containing their variables. That is explicitly declared undefined behavior in perlop.
See Matching and order of evaluation for a lively and excellent free-for-all on the subject.
| [reply] |
Re: order of arguments evaluated
by dave_the_m (Monsignor) on May 17, 2005 at 09:19 UTC
|
There seems to have been a lot of erroneous information given out in the various replies above. It just so happens that the args are evaluated left-to-right, but since the first arg is a pass-by-reference of $var, it gets modified by the subsequent ++; it's a bit like
$ perl -le'sub f {$var++; print $_[0]} f $var'
1
$
Dave. | [reply] [d/l] |
|
|
this, I must say, is a marvelous turn of events. I'm almost glad I gave the bad advice, just for learning the above.
ie, since ',' always evaluates its left argument first and is listed as left-associative, this means Perl would definitely process every argument list left-to-right?
And also, $var++ is passed by value, while ++$var is passed by reference, so print($var++,++$var,$var++) would print 143...
truly magnificent, albeit mildly confusing..
In any case, thanks for the correction, Dave
| [reply] |
Re: order of arguments evaluated
by ivancho (Hermit) on May 17, 2005 at 06:40 UTC
|
actually, saying that evaluation is in any fixed order is a bad idea. If you try the same code, but with 3 variables:
sub printit{ print @_; }
my $var = 1;
&printit($var,$var++,$var);
you will get 212 - would you say now that evaluation starts from the middle?
what happens, I think, is that Perl takes the argument list, and applies any mutators (like ++) in there, before evaluating the rest.
As a general afterthought, having dependent arguments with mutators in a function call, or just in the same statement, sounds like a bad idea. For a start, you might introduce 2 mutators at the same time - which is likely to produce rubbish... how would you expect something like
my $a = NumberObject->new(5);
print SumNumbers($a, $a->square_me(), $a->double_me());
to behave? | [reply] [d/l] [select] |
|
|
how would you expect something like ... to behave?
With a defined execution order, this question, the OP's problem and all the previous and future discussions surrounding this subject would be trivial to answer.
Or, more likely, simply would never have arisen.
And the benefits that the Perl coder gets from EO being undefined is?
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"Science is about questioning the status quo. Questioning authority".
The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.
| [reply] |
|
|
| [reply] |
|
|
|
|
|
|
|
$i += $i++ - ++$i;
Can we agree that that expression is dog ugly? What exactly should the value of $i be after evaluation? Why? Think about 0**0. What should that value be? You can devise arguments that it could be either 0 or 1 (i.e. $anything**0==1 but 0*$anything==0). Assigning meaning to the original expression can be done, but ugly expressions like that should be avoided in the first place. Perl's designers decided that it would be hard to prevent people from writing ugly code, but they're going to wash their hands of the whole enterprise by saying "bah, if you want to shoot yourself in the foot, feel free. Just be aware that we aren't making promises that your program will work properly in the future."
| [reply] [d/l] [select] |
|
|
|
|
|
|
|
Interestingly similar code in Java produces the expected result "112"
public class PrecedenceTest {
public PrecedenceTest(){
int i = 1;
printIt(i, i++, i);
}
protected void printIt(int i, int j, int k){
System.out.println( i+"" + j+""+ k+"" );
}
public static void main(String[] args){
PrecedenceTest p = new PrecedenceTest();
}
}
Thanks to a colleague for writing this :-) | [reply] [d/l] |
Re: order of arguments evaluated
by polettix (Vicar) on May 17, 2005 at 06:58 UTC
|
| [reply] |
Re: order of arguments evaluated
by JamesNC (Chaplain) on May 17, 2005 at 16:47 UTC
|
You could use reverse I would think it is better to fix your code. Perhaps named args? They help document, avoid confusion and set defaults.
use strict;
&foo( x=> 10, );
sub foo {
my %args = @_;
my $x = $args{'x'} || 0;
my $y = $args{'y'} || 0;
print "Args: x=> $x , y=> $y\n";
}
| [reply] [d/l] |
|
|
let me charge in with my new found understanding, limited as it may be.
reverse is unlikely to solve the original problem:
printit($var,$var++);
will produce exactly the same as
printit(reverse($var++,$var)), namely '21'.
Also, the named args would suffer from exactly the same issue - have you tried foo(x => $var, y => $var++) with your construction? After all, it is just another way of writing foo("x",$var,"y",$var++)
From what I gather, Perl always sends things effectively by reference - and that reference is decided in a left-to-right order over the arguments. The thing is, when it sees $var++, it copies the value of $var to a temporary variable, increases $var, but sends a reference to the temp. From there onwards, no changes in $var would have influence on what is sent from the spot of $var++ - nothing else is referencing that temp var. Where $var is, on the other hand, we have already decided to send the reference to $var - but the other terms may also have access to that piece of memory, in which case only what is there at the end of the entire argument list matters. You could try and fix the value in each slot, by sending $var+0, or whatever, but that looks evil
Additionally, if we think about '+' in a functional sort of way, ie $x + $y being actually +($x,$y)... or (+ $x $y), whatever your poison is, then we can solve any sort of conundrums, like what the code below would produce
my $m = 20;
print ++$m + $m++;
(ie, 43), or why, for example, the following are completely different:$var++ + ($var + $var)
and$var++ + $var + $var
perlop seems to be misleading in that sense:
Auto-increment and Auto-decrement:
``++'' and ``--'' work as in C. That is, if placed before a variable, they increment or decrement the variable by one before returning the value, and if placed after, increment or decrement after returning the value.
| [reply] [d/l] [select] |
Re: order of arguments evaluated
by monarch (Priest) on May 31, 2005 at 02:39 UTC
|
I recently implemented the following code.. I THINK I'm safe but I'm not 100% sure.. I would tend to shy away from such code..
my $rownew = 0;
foreach my $box ( @boxes ) {
if ( $rownew ? 1 : $rownew++ ) {
print( "," );
}
print( $box );
}
This, too, depends on the fact that $rownew is evaluated on the left hand side of the ? operator before the result. It's one of the few times, if ever, that I would want to be silly enough to mix ++ and dependant code on the one line. | [reply] [d/l] [select] |
|
|
That could be better written as
print join ',', @boxes;
unless you're concerned about the joined string being enormous, in which case I'd probably say
my $printed = 0;
foreach my $box ( @boxes ) {
print ',' if $printed++;
print $box;
}
But your code is perfectly safe. The alternatives are only evaluated if the corresponding condition indicates that they should be.
Caution: Contents may have been coded under pressure.
| [reply] [d/l] [select] |
|
|
Indeed both are good suggestions, but the context was putting together HTML tables, hence a simple join wasn't satisfactory.
The second solution was also good, but I was concerned about integer wrap-around, which could potentially evaluate to zero in the case of a HUGE table (being the paranoid programmer that I am, even though the likelihood of generating a 4,294,967,296 row table was unlikely).
Hence the dodgy trinary operator statement.
| [reply] |
|
|
| A reply falls below the community's threshold of quality. You may see it by logging in. |