in reply to Flattening out arguments to splice

What you're seeing is because splice has a prototype, and you can use prototype to see it (this is on Perl v5.26):

$ perl -le 'print prototype("CORE::splice")//"undef"' \@;$$@

(From Perl v5.14 thru v5.22, the prototype was +;$$@, because of the removed autoderef.)

As of 5.26, you can use the & sub calling to avoid the prototype, as in &CORE::splice(@args);.

But since that's not available in all versions of Perl, you may in fact need to resort to conditionals, even if it seems "clumsy" :-) For example, because some functions change their behavior based on how many arguments they get, I had to do exactly that in Tie::Handle::Base - see my binmode and open wrappers.

However, the arguments to splice have clear defaults, so as tybalt89 and AnomalousMonk already showed you don't necessarily need to resort to a long if-elsif chain. This passes all the tests in t/op/splice.t*:

sub mysplice (\@;$$@) { my ($arr,$off,$len,@list) = @_; splice @$arr, $off//0, $len // @$arr - ($off//0), @list; }

And unlike CORE::splice, you can use a &mysplice call to ignore the prototype (before v5.26), or change the prototype and arguments however you like.

* Full test code:

use warnings; use strict; use Test::More; sub mysplice (\@;$$@) { my ($arr,$off,$len,@list) = @_; splice @$arr, $off//0, $len // @$arr - ($off//0), @list; } my @a = (1..10); sub j { join(":",@_) } is( j(mysplice(@a,@a,0,11,12)), '', 'return value of splice when nothi +ng is removed, only added'); is( j(@a), j(1..12), '... added two elements'); is( j(mysplice(@a,-1)), "12", 'remove last element, return value'); is( j(@a), j(1..11), '... removed last element'); is( j(mysplice(@a,0,1)), "1", 'remove first element, return value'); is( j(@a), j(2..11), '... first element removed'); is( j(mysplice(@a,0,0,0,1)), "", 'emulate shift, return value is empty +'); is( j(@a), j(0..11), '... added two elements to beginning of the list' +); is( j(mysplice(@a,5,1,5)), "5", 'remove and replace an element to the +end of the list, return value is the element'); is( j(@a), j(0..11), '... list remains the same'); is( j(mysplice(@a, @a, 0, 12, 13)), "", 'push two elements onto the en +d of the list, return value is empty'); is( j(@a), j(0..13), '... added two elements to the end of the list'); is( j(mysplice(@a, -@a, @a, 1, 2, 3)), j(0..13), 'splice the whole lis +t out, add 3 elements, return value is @a'); is( j(@a), j(1..3), '... array only contains new elements'); is( j(mysplice(@a, 1, -1, 7, 7)), "2", 'replace middle element with tw +o elements, negative offset, return value is the element' ); is( j(@a), j(1,7,7,3), '... array 1,7,7,3'); is( j(mysplice(@a,-3,-2,2)), j(7), 'replace first 7 with a 2, negative + offset, negative length, return value is 7'); is( j(@a), j(1,2,7,3), '... array has 1,2,7,3'); # Bug 20000223.001 (#2196) - no test for splice(@array). Destructive +test! is( j(mysplice(@a)), j(1,2,7,3), 'bare splice empties the array, retur +n value is the array'); is( j(@a), '', 'array is empty'); # Tests 11 and 12: # [ID 20010711.005 (#7265)] in Tie::Array, SPLICE ignores context, bre +aking SHIFT my $foo; @a = ('red', 'green', 'blue'); $foo = mysplice @a, 1, 2; is( $foo, 'blue', 'remove a single element in scalar context'); @a = ('red', 'green', 'blue'); $foo = shift @a; is( $foo, 'red', 'do the same with shift'); # Bug [perl #30568] - insertions of deleted elements @a = (1, 2, 3); mysplice( @a, 0, 3, $a[1], $a[0] ); is( j(@a), j(2,1), 'splice and replace with indexes 1, 0'); @a = (1, 2, 3); mysplice( @a, 0, 3 ,$a[0], $a[1] ); is( j(@a), j(1,2), 'splice and replace with indexes 0, 1'); @a = (1, 2, 3); mysplice( @a, 0, 3 ,$a[2], $a[1], $a[0] ); is( j(@a), j(3,2,1), 'splice and replace with indexes 2, 1, 0'); @a = (1, 2, 3); mysplice( @a, 0, 3, $a[0], $a[1], $a[2], $a[0], $a[1], $a[2] ); is( j(@a), j(1,2,3,1,2,3), 'splice and replace with a whole bunch'); @a = (1, 2, 3); mysplice( @a, 1, 2, $a[2], $a[1] ); is( j(@a), j(1,3,2), 'swap last two elements'); @a = (1, 2, 3); mysplice( @a, 1, 2, $a[1], $a[1] ); is( j(@a), j(1,2,2), 'duplicate middle element on the end'); # splice should invoke get magic ok( ! Foo->isa('Bar'), 'Foo is not a Bar'); mysplice @Foo::ISA, 0, 0, 'Bar'; ok( Foo->isa('Bar'), 'splice @ISA and make Foo a Bar'); # Test arrays with nonexistent elements (crashes when it fails) @a = (); $#a++; is sprintf("%s", mysplice @a, 0, 1), "", 'splice handles nonexistent elems when shrinking the array'; @a = (); $#a++; is sprintf("%s", mysplice @a, 0, 1, undef), "", 'splice handles nonexistent elems when array len stays the same'; @a = (1, 2, 3); my @args = (\@a, 1, 2, $a[2], $a[1]); &mysplice( @args ); is( j(@a), j(1,3,2), 'swap last two elements (with &)'); done_testing;

Update: Actually, I had to fiddle with the read-only test slightly, I don't have the time right now to investigate why Internals::SvREADONLY didn't seem to work. <update2> I was testing on v5.26, but the readonly test, which I got from blead, wasn't actually added until v5.27.5. So I've just removed that test so that the code matches v5.26. (I adjusted the above link to t/op/splice.t accordingly.) </update2>