Perl semicolon execution order

Forgive the poor readability of my examples, but this code is for playing in codes, not for production code.

Consider the following script:

print'+'x$z,($z=1,$w)?'':$_ for 1..3; 

This prints, as you would expect, 1+2+3 . The variable $z not initially assigned, so '+'x$z is evaluated as empty; after that, $z set to 1, so '+'x$z now evaluated as + .

However, if I change this so that $z contains + itself:

 print$z,($z='+',$w)?'':$_ for 1..3; 

script now prints +1+2+3 . This seems to suggest me that the execution order is different, but I don't understand why.

What are the exact rules regarding the execution order that make these two examples behave differently? Is the execution order still clear?

+4
source share
3 answers

Arguments are passed by reference in Perl.

 print $z, ($z='+',$w) ? '' : $_; 

mostly

 { local @_; alias $_[0] = $z; alias $_[1] = ($z='+',$w) ? '' : $_; &print; } 

Since $_[0] smoothed to $z , changes in $z are reflected in $_[0] , even if these changes occur after the argument is evaluated.

You can see the same effect in the following:

 my $x = 3; sub f { ++$x; print("$_[0]\n"); } f($x); # 4 
+4
source

Here is my attempt to sort out your two examples. Consider this script:

 use strict; use warnings; use Data::Dumper; sub dd { print Dumper(\@_) } my $z = 0; dd($z + 2, ($z = 1)); # Similar to your Version 1. dd($z, ($z = 1)); # Similar to your Version 2. 

Output with comments:

 $VAR1 = [ 2, # The constant 2. 1 # $z by reference, which prints as 1. ]; $VAR1 = [ 1, # $z by reference. ${\$VAR1->[0]} # Ditto. ]; 

In version 1, Perl cannot pass $z + 2 directly to dd() . He must appreciate the expression. The result of this estimate (constant 2) is passed as the first argument. The second argument is also evaluated: $z set to 1, the return value of the assignment is $z , and then $z is passed by reference dd() .

In version 2, Perl can simply pass the first argument directly by reference: there is no need to evaluate a larger expression. The second argument is the same as in version 1. As a result, dd() gets the same variable twice, as shown in the output of Data::Dumper .

+1
source

Original answer

You need to run this through perl -MO=Deparse,-p . The first bit of code shows this:

 print(('+' x $z), ((($z = 1), $w) ? '' : $_)) foreach (1 .. 3); 

But the second bit of code shows this:

 print($z, ((($z = '+'), $w) ? '' : $_)) foreach (1 .. 3); 

Confused and Carefree

Apparently, this turned out to be insufficient to sufficiently explain some issues. It should not have been, as I considered it perfectly clear.

The decision mistakenly claims that this is somehow due to the fact that Perl passes scalar variables by an implicit reference. This has nothing to do with it. This is a simple question about the priority and order of evaluation. I assumed Deparse's exit should make this clear.

Apparently, some of them are still confused.


First version

Very good, here is your explanation that you spend on a silver dish for you.

It:

 print'+'x$z,($z=1,$w)?'':$_ for 1..3; 

equivalent, kindly provided by Deparse and some additional formation:

 { ($w, $z) = (undef, undef); for (1..3) { print(("+" x $z), ((($z = 1), $w) ? "" : $_)) } } continue { print "\n"; } 

Now, by unrolling the cycle and separating what happens when it is created:

 { ($w, $z) = (undef, undef); { local $_ = 1; $temp = "+" x $z; # $z is undef $z = 1; print $temp, $_; } { local $_ = 2; $temp = "+" x $z; # $z is 1 $z = 1; $_ = $_; print $temp, $_; } { local $_ = 3; $temp = "+" x $z; # $z is 1 $z = 1; $_ = $_; print $temp, $_; } } continue { print "\n"; } 

All three of them produce identical output: 1+2+3 .

Second version

Now we will start again with the original:

 print$z,($z='+',$w)?'':$_ for 1..3; 

and create a version to delete:

 { ($w, $z) = (undef, undef); for (1..3) { print($z, ((($z = "+"), $w) ? "" : $_)); } } continue { print "\n"; } 

followed by the loop version:

 { ($w, $z) = (undef, undef); { local $_ = 1; $z = "+"; print $z, $_; } { local $_ = 2; $z = "+"; print $z, $_; } { local $_ = 3; $z = "+"; print $z, $_; } } continue { print "\n"; } 

All three versions, for reasons I REALLY HOPE THAT YOU NEED TO CLEAN, will print the same result: +1+2+3 .


For further enlightenment

The best way to track what happens when you need to trace it:

 tie $z, "Tie::Trace", "z"; tie $w, "Tie::Trace", "w"; ($w, $z) = (undef, undef); print'+'x$z,($z=1,$w)?'':$_ for 1..3; print "\n"; { ($w, $z) = (undef, undef); for (1..3) { print(("+" x $z), ((($z = 1), $w) ? "" : $_)) } } continue { print "\n"; } { ($w, $z) = (undef, undef); { local $_ = 1; $temp = "+" x $z; # $z is undef $z = 1; print $temp, $_; } { local $_ = 2; $temp = "+" x $z; # $z is 1 $z = 1; $_ = $_; print $temp, $_; } { local $_ = 3; $temp = "+" x $z; # $z is 1 $z = 1; $_ = $_; print $temp, $_; } } continue { print "\n"; } ($w, $z) = (undef, undef); print$z,($z='+',$w)?'':$_ for 1..3; print "\n"; { ($w, $z) = (undef, undef); for (1..3) { print($z, ((($z = "+"), $w) ? "" : $_)); } } continue { print "\n"; } { ($w, $z) = (undef, undef); { local $_ = 1; $z = "+"; print $z, $_; } { local $_ = 2; $z = "+"; print $z, $_; } { local $_ = 3; $z = "+"; print $z, $_; } } continue { print "\n"; } package Tie::Trace; sub TIESCALAR { my($class, $name, $value) = @_; return bless { NAME => $name, VALUE => undef, } => $class; } sub FETCH { my($self) = @_; my $name = '$' . $self->{NAME}; my $value = $self->{VALUE}; print STDERR "[reading value ", defined($value) ? $value : "undef", " from $name]\n"; return $value; } sub STORE { my($self, $value) = @_; my $name = '$' . $self->{NAME}; print STDERR "[writing value ", defined($value) ? $value : "undef", " into $name]\n"; $self->{VALUE} = $value; return $value; } 

When you run this, it produces this pretty nice conclusion:

 [writing value undef into $w] [writing value undef into $z] [reading value undef from $z] [reading value undef from $z] [writing value 1 into $z] [reading value undef from $w] [reading value 1 from $z] [reading value 1 from $z] [writing value 1 into $z] [reading value undef from $w] [reading value 1 from $z] [reading value 1 from $z] [writing value 1 into $z] [reading value undef from $w] 1+2+3 [writing value undef into $w] [writing value undef into $z] [reading value undef from $z] [reading value undef from $z] [writing value 1 into $z] [reading value undef from $w] [reading value 1 from $z] [reading value 1 from $z] [writing value 1 into $z] [reading value undef from $w] [reading value 1 from $z] [reading value 1 from $z] [writing value 1 into $z] [reading value undef from $w] 1+2+3 [writing value undef into $w] [writing value undef into $z] [reading value undef from $z] [reading value undef from $z] [writing value 1 into $z] [reading value 1 from $z] [reading value 1 from $z] [writing value 1 into $z] [reading value 1 from $z] [reading value 1 from $z] [writing value 1 into $z] 1+2+3 [writing value undef into $w] [writing value undef into $z] [writing value + into $z] [reading value undef from $w] [reading value + from $z] [writing value + into $z] [reading value undef from $w] [reading value + from $z] [writing value + into $z] [reading value undef from $w] [reading value + from $z] +1+2+3 [writing value undef into $w] [writing value undef into $z] [writing value + into $z] [reading value undef from $w] [reading value + from $z] [writing value + into $z] [reading value undef from $w] [reading value + from $z] [writing value + into $z] [reading value undef from $w] [reading value + from $z] +1+2+3 [writing value undef into $w] [writing value undef into $z] [writing value + into $z] [reading value + from $z] [writing value + into $z] [reading value + from $z] [writing value + into $z] [reading value + from $z] +1+2+3 

Summary

Now, I have barely demonstrated that what is actually happening here has nothing to do with passing by reference. This is only due to the order of evaluation, and nothing more.

-2
source

Source: https://habr.com/ru/post/1347322/


All Articles