@s = qw(a b);
$z = shift(@s) . shift(@s);
print $z;
guaranteed to print "ab"?
I asked this on comp.lang.perl.misc, but nobody seemed to know
anything. I thought I remembered that Larry had made a pronouncement
about this kind of thing, or that it had been discussed here before,
but I couldn't remember if that was true, or, if it was, what the
outcome was.
Mark-Jason Dominus m...@plover.com
I think so, so long as associativity and precedence order of perl stays
the same:
perldoc perlop
> left terms and list operators (leftward)
> [snip]
> left + - .
So your example must evaluate as:
$z = shift(@s);
$z .= shift(@s);
And my perls all print "ab" when your code is fed to them.
@signature = qw(dan kogai);
$signature = shift(@author) . shift(@author);
print $signature;
IIRC the same mistake was made on c.l.p.misc : neither associativity
nor precedence are related to evaluation order.
The summarizer's urge is to post a link to the relevant thread :
http://groups.google.com/groups?selm=bhok6j%2470f%241%40plover.com
--
Aagh, that's right. For (1+2)*(3+4), we may evaluate 1+2 first, 3+4
first, or even both at the same time (with multiprocessing). For such
(very likely most) cases you can safely evaluate both terms in parallel.
> The summarizer's urge is to post a link to the relevant thread :
>
> http://groups.google.com/groups?selm=bhok6j%2470f%241%40plover.com
I've read it and found Benjamin's example interesting.
$x{foo} ||= keys %x; # %x is (foo => 1) in current perl
$y{foo} = keys %y; # %x is (foo => 0) in current perl
I also googled 'perl "order of evaluation"' and the found that similar
discussion was already done here at perl5-porters.
http://www.perl.com/lpt/a/2000/12/p5pdigest/THISWEEK-20001217.html
It appears back then the order of evaluation remains undefined so I
reckon it is still undefined as of perl 5.8.
In the discussion above t Nicholas Clark points that keeping the order
undefined allows for flexibility in the implementation and I kind of
agrees with his point; Since multiprocessing is already a reality, we
should allow future perl to allow terms to be evaluated in parallel.
Hmm.... But does that mean that mjb's example may print 'aa' when
shift(@a) is evaluated simultaneously?
@me = qw(dan kogai); $me = shift(@me) . shift(@me); print $me;
No, because that would be incorrect. shift() modifies its argument :
that means that it should have the conceptual equivalent of an exclusive
lock on it, and thus two shift()s on a same array will be executed
sequentially.
IF we CORRECTLY implement the future perl. Should we make a test suite
for future perls to come ? But what should we do on that test suite?
$a = shift(@a) . shift(@a); ok( $a ne 'aa' and scalar(@a) == 0 );
Is the code like this good enough?
> that means that it should have the conceptual equivalent of an
> exclusive
> lock on it, and thus two shift()s on a same array will be executed
> sequentially.
Exclusive lock is not good enough because for exclusive lock to work,
either shift() must be evaluated before the other but we make no such
guarantee; they MAY be evaluated REALLY AT THE SAME TIME. So the
serialization must occur at opcode generation level, not execution
level.
If we want future optimizer to allow parallel evaluation, it should try
to do so when and only when it is safe to do so. Frankly, I am not
sure if we can make our compiler that smart. Simply looking at an
expression and see if the same variable does not appear twice is not
good enough because we have reference now.
@a = (a b); $ra = \@a; $a = shift(@a) . shift(@$ra);
Can we safely optimize the code above?
While thinking about this, I remarked that I wrote
several times something like
sub foo($$) {
my ($x, $y) = (shift, shift);
...
}
to copy the @_ elements.
-- there's an instance of this statement in Test::LongString
for example. The implicit assumption is that C<,> guarantees
evaluation order. Like the comma operator in C IIRC.
(On the other hand the Test::LongString function that uses
this idiom is symmetric in its argument order.)
I was watching this discussion and was wondering whether this idiom
is in danger:
sub accessor { shift->handler( 'accessor',@_ ) }
I don't think it is, but what do you guys think?
Liz
I don't think any idiom is in danger, but obviously
the lhs of -> should be evaluated first to perform method
dispatch. More or less.
Indeed. It's the "more or less" that I'm worried about ;-)
Liz
The above is dangerous, but works for all versions of Perl, as far
as I know. However,
sub accessor { shift->handler( 'accessor', shift ) }
does not always produce the same result.
As stated by someone before, precedence and associativity only
determine how to read the expression. Simply said: they allow you
to write Perl in stead of LISP; you may leave out some parenthesis.
However... there are exceptions. In some languages, some operators do
enforce order. For instance the && in C and Perl, but not AND in Pascal.
When you write A && B, it is guarenteed that A is evaluated before B.
In the C language, the comma does not define the order of evaluation,
which is cause of many conversion problems. In Perl, the comma is
strictly evaluated from left to right in scalar context (explicitly
described perlop).
In LIST context, the comma is not an operator at all, but an expression
separator like ';' And therefore, the comma is not in for re-ordering
in an argument list.
That's my opinion on the docs. Results may vary.
--
MarkOv
------------------------------------------------------------------------
drs Mark A.C.J. Overmeer MARKOV Solutions
Ma...@Overmeer.net solu...@overmeer.net
http://Mark.Overmeer.net http://solutions.overmeer.net
The order of evaluation is dependent on how perl turns a tree of ops
into a sequence of ops to be evaluated one at a time.
Perl starts with a tree:
[Windows 95] C:\WINDOWS>perl -MO=Concise -e "shift(@a) . shift(@b)"
a <@> leave[t1] vKP/REFC ->(end)
1 <0> enter ->2
2 <;> nextstate(main 5 -e:1) v ->3
9 <2> concat[t5] vK/2 ->a
5 <1> shift sK/1 ->6
4 <1> rv2av[t2] lKRM/1 ->5
3 <> gv s ->4
8 <1> shift sK/1 ->9
7 <1> rv2av[t4] lKRM/1 ->8
6 <> gv s ->7
-e syntax OK
(Without those numbers at the front of each line, innitially.)
Then, it turns that tree into a linear sequence of operations, to
perform one at a time (that's what those numbers represent).
Remember, perl5 is stack based, so the ops have to be done in the right
order, so that the ops using their results in turn get those arguments
in the right order.
The "gv" op gets a glob, and pushes it onto the stack.
Then "rv2av" pops a glob from the stack, fetches it's array slot, and
pushes the array onto the stack.
Then, "shift" pops an array from the stack, shifts off the first value,
and pushes the result onto the stack.
After we've done that twice, there are two strings on the stack.
Then, "concat" pops two items from the stack, concatenates them
together, then pushes the result onto the stack.
If shift(@b) had been evaluated before the first shift(@a), the two
strings would be on the stack in opposite order.
Now, obviously any change which makes shift(@s).shift(@s) produce "ba"
instead of "ab" needs to *not* change the apparent behavior of
shift(@a).shift(@b).
Thus, if the right side of "." were evaluated before the left side of
".", then the "concat" operator would need to be changed so that it
treats its two inputs (the top two items on the stack) in the opposite
order.
We could indeed do this (and of course change how the tree is linearized
to make the ops run in sequence), but it would be pointless... I can't
think of any way that such a change could be to anyone's advantage.
Thus, while order of evaluation isn't set in stone, it's *quite*
unlikely to change. At least, not as long as we retain the current
stack based design.
In ponie, on the other hand, it would be quite possible for the second
argument to concat to be evaluated before the first, since the results
of those shift() operations will be going into registers, not onto the
stack; this gives us the freedom to move around their order of
evaluation without changing anything else, not even the order that the
concat operator takes it's args (just switch around the order of the
arguments/registers which are passed to it).
Of course, since it would be non-backwards-compatible to have ponie
evaluate things in a different order than the current perl5, that's
rather unlikely.
--
$a=24;split//,240513;s/\B/ => /for@@=qw(ac ab bc ba cb ca
);{push(@b,$a),($a-=6)^=1 for 2..$a/6x--$|;print "$@[$a%6
]\n";((6<=($a-=6))?$a+=$_[$a%6]-$a%6:($a=pop @b))&&redo;}
The order of evaluation is dependent on how perl turns a tree of ops
);{push(@b,$a),(X-Mozilla-Status: 0009--$|;print "$@[$a%6
> Is this:
>
> @s = qw(a b);
> $z = shift(@s) . shift(@s);
> print $z;
>
> guaranteed to print "ab"?
>
> ... I thought I remembered that Larry had made a pronouncement about
> this kind of thing,
Larry has pronounced that its undefinedness was a mistake in Perl 5 that
will be rectified in Perl 6:
http://groups.google.com/groups?threadm=20030301172639.GA29036%40wall.org
Smylers
Cool.
We definitively need a p5p<->p6l bridge...
Is the statement correct? Is the example too complex?
diff -u old/pod/perlop.pod new/pod/perlop.pod
--- old/pod/perlop.pod Mon Sep 8 21:15:06 2003
+++ new/pod/perlop.pod Mon Sep 8 22:01:38 2003
@@ -404,6 +404,17 @@
Using "or" for assignment is unlikely to do what you want; see below.
+=head2 Evaluation order
+
+All evaluated operands are evaluated left to right as
+they appear, regardless of associative grouping.
+
+ @_ = qw(g f e d c b a);
+ print join(",",
+ shift().shift(), shift(),
+ sort shift().shift(), shift().shift()); # prints "gf,e,ba,dc"
+
+
=head2 Range Operators
Binary ".." is the range operator, which is really two different
Not until there are regression tests to test this. And until there
is commitment not to change the order of evaluation.
> diff -u old/pod/perlop.pod new/pod/perlop.pod
> --- old/pod/perlop.pod Mon Sep 8 21:15:06 2003
> +++ new/pod/perlop.pod Mon Sep 8 22:01:38 2003
> @@ -404,6 +404,17 @@
>
> Using "or" for assignment is unlikely to do what you want; see below.
>
> +=head2 Evaluation order
> +
> +All evaluated operands are evaluated left to right as
> +they appear, regardless of associative grouping.
> +
> + @_ = qw(g f e d c b a);
> + print join(",",
> + shift().shift(), shift(),
> + sort shift().shift(), shift().shift()); # prints "gf,e,ba,dc"
> +
> +
Abigail
This is not true.
$ perl -le '$a{shift()} = shift; print %a' 1 2
21
Regards,
Adi
+they appear, regardless of associative grouping. Assignment
+operations may be considered to be two separate expressions,
+with the right hand side evaluated first.
What else?
--
David Nicol / kernel 2.6.0 is pretty whippy
The short-circuting assignment operators are an exception to the
exception.
This :-)
$ perl -le 'sub a { print "a" } sub b { print "b" } (a)[b]'
b
a
Regards,
Adi
It occurs to me that exceptions don't prove rules, rather they do the
opposite.
Perhaps, for the time being, it's better to leave Perl to do what it
does, and let the future sort itself out by itself.
Alex Gough
--
"Life," said Marvin dolefully, "loathe
it or ignore it, you can't like it."
> > What else?
>
> This :-)
>
> $ perl -le 'sub a { print "a" } sub b { print "b" } (a)[b]'
> b
> a
>
> Regards,
> Adi
so we're up to, in general left-to-right, except the RHS is always
before of the LVALUE, except for self-assignment, when the LVALUE
is part of the RHS and does not get reevaluated.
Also the index of an array is evaluated before a dynamic
array expression, as Adi points out. Curiously this does not
occur with hashes, only arrays.
perl -le 'sub a { print "a" } sub b { print "b" } @{[4 => a]}[b()]'
b
a
perl -le 'sub a { print "a" } sub b { print "b" } ${{4 => a}}{b()}'
a
b
More specificly, only array slices
perl -le 'sub a { print "a" } sub b { print "b" } ${[4 => a]}[b()]'
a
b
Hash slices evaluate the slice target first too
perl -le 'sub a { print "a" } sub b { print "b" } @{{4 => a}}{b()}'
b
a
so
(a)[b] # a slice, b first
[a]->[b] # not a slice, a first
Wow.
Is there any sense to this? The lookup of a sliced container is
not skipped when the key expression returns a null list:
perl -le 'sub a { print "a" } sub b { print "b";() } (a)[b()]'
b
a
was
that an optimization that was planned but never realized? It would
break some very odd code that considers fetching null slices out of
tied containers significant, it would also break designs that rely
on autovivification in such cases.
It sounds like the answer to my question was 'no'. Thanks a lot!