'Why is `splice(@_, 0, shift)` safe?

The perl 5.18.2 documentation of splice has this example:

my(@a) = splice(@_,0,shift);
my(@b) = splice(@_,0,shift);

And I wonder: If @_ is evaluated before the shift there would be one item too much for the result to be correct. So conceptually the shift must be performed first. However in C they teach you that you should never rely on a specific order of evaluation of actual parameters (shift modifies @_).

So is that code only working because @_ is passed as a reference (to be able to change it), and the shift being evaluated before splice can access @_?

A Bit of History

I found the example goes some way back to 1996 (at least) and the book (page 219; a comment on page 535 suggests it may even come along from Perl 4):

WALL, Larry, Tom CHRISTIANSEN und Randal L. SCHWARTZ, 1996. Programming Perl. 2. Sebastopol, CA 95472, U.S.A.: O’Reilly & Associates, Inc. ISBN 1-56592-149-6



Solution 1:[1]

Because @_ itself is being passed to the sub (rather than being flattened) because splice is expected to modify it. And Perl always passes by reference.


With a normal sub, @_ would get flattened. But being an operator, splice receives the array instead. And not a copy of it. Not only would that be inefficient, but splice is expected to modify it. So the array itself is placed on the stack. (In C terms, this is a pointer. All Perl variables are pointers. The fact that only pointers are being exchanged under the hood is why Perl exhibits pass-by-reference semantics.)

Perl evaluates lists from left to right, so @_ is placed on the stack, then 0 is placed on the stack, then shift is evaluated modifying @_ and placing the removed value on the stack.

It doesn't matter that @_ is modified when it's found on the stack. As long as these things happen before the splice is performed — and they are — it works perfectly fine.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1