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

Viewed 120

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

1 Answers

Because @_ itself is being passed to splice (rather than being flattened or copied) because splice is expected to modify it.


With a normal subroutine, an array in the argument list would get flattened. But splice is an operator, so it's not limited to the behaviour of subroutines.

Perl provides the array to splice instead. And not a copy of it. The array itself is placed on the stack. This allows it to be modified, and it's more efficient as a bonus.

(In C terms, "the array" 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.

Related