I hate unpacking sub calls with shift

Perl community has moved away from using special predefined Perl variables such as $(, $), $:, $!, $^H, $/ or many others without explicitly commenting their purpose. But why are we still using shift for sub params? i.e.:

sub foo {
    my $bar = shift;
}

Why is it still fine within the community to skip the @_ ? If we promote shift, then lets use pop as well? Why not? it looks nice:

sub foo {
    return pop, shift;
}

Though I am sure someone already uses it.. how about those that use shift at line 100 inside the sub ? I hate that.. It makes really hard to follow code, for instance is it sixth or seventh unpacked argument?.. I think it’s bad practise.

I like when code is consistent and self-documenting. I love when the very first line inside the sub lists expected parameters! Just look how beautiful and tidy it looks:

sub foo {
    my ( $foo, $bar, $baz ) = @_;
}

You might think that it is convenient to use shift in cases like:

# EXAMPLE1
sub init {
    shift;
    my %args = @_;
}
sub foo {
    my $bar = shift // ‘default’;
}

# EXAMPLE2
sub foo { shift->call() }

# EXAMPLE3
sub extends {
    my $meta = shift;
    if ( @_ ) {
        print “foo bar baz”;
    }
    return @_;
}

# EXAMPLE4
sub foo {
    new $_[0], shift;
}
sub before {
    Foo::Bar::baz(shift, ‘before’, \@_);
}

But it’s horrible for newcomers! You are hurting them! What did they do to you?

  • See EXAMPLE1 and imagine you didn't understand ‘shift’. Next you google ‘Perl shift’ and probably find irrelevant information. If you add @_ i.e. 'shift( @_ )', you might have saved someone an hour.
  • how about EXAMPLE2 ? No semicolon.. no return.. and you can find this in many, many modules out there.
  • How about EXAMPLE3 ? Removing first item from @_ and then actually reusing @_ twice.
  • EXAMPLE4… aghhhh.. mixing two together..

Yet, shift might look tidier in compare to $_[0] when you are after performance and don’t want to assign named variables. But in 99% it doesn’t matter and if you need performance - document the need.

Lets start preparing for new wonderful Peter Martini’s sub signatures and tidy up.

8 Comments

Generally speaking I use shift for the invocant of method calls, or arguments I consider to be especially privileged. (If those arguments happened to be at the end of @_, I'd use pop, but that's not often the case.)

Other arguments get assigned via list assignment from @_.

The exception is very short (generally one line) subs where I might just use $_[0] and friends directly for either speed or conciseness.

> This one is very good:

No, it's not - it uses Devel::Declare, which is a giant ball of crack that is actively discouraged by its authors and everyone who understands the improvements made in 5.14 that make this ball of crack unnecessary. :)

We have started using https://metacpan.org/pod/Function::Parameters for everything at work. It's great. It uses perl's built in keyword api, not Devel::Declare. And the support for parameter type constraints makes our code a lot cleaner, safer, and self documenting.

Function::Parameters is great but it won't become recommended best practice unless it is a core module or required by Moo.*.

Newcomers need to understand that sub call arguments are passed in an array. And to appreciate the power of arrays, a programmer needs to understand how shift, unshift, pop, push etc are array operators.

I agree that placing a shift deep inside a subroutine is not helpful but this is more a poor coding style. One could also place a @_ on line 100 of the code.

My five cents-it is no big deal.

Perl community has moved away from using special predefined Perl variables such as $(, $), $:, $!, $^H, $/ or many others without explicitly commenting their purpose

$! is common enough that it shouldn't need comments, though?

If the argument is that people learning perl won't understand them, I'd disagree:

open my $fh, '

tends to be covered very early in most tutorials, and is also described in perldoc perlopentut. To some extent the same applies to $/, reading in paragraph mode or in fixed chunks is something that you encounter very early.

Writing shift; as shift(@_); doesn't seem like an improvement. Surely the same would apply to /.../ vs. $_ =~ /.../, or () around all function parameters, or indeed any of the other shortcuts the language offers? Rather than avoiding perl features because they might confuse newcomers, surely it makes more sense to write the best code you can, so that newcomers can learn from the Perl idioms that make the language so expressive?

I'd be surprised if using shift(@_) saved anyone time, given the amount of code already out there - including most tutorials and books - which already uses the 'my $var = shift;' idiom. Also, it seems that search results for "Perl shift(@_)" are not really any better than "Perl shift", at least according to Google.

If the documentation for shift() isn't sufficient then perhaps it'd help to submit a patch with better wording? The current (5.20) text doesn't go into much detail, maybe there's a better way to phrase it.

Also, not sure what you mean about performance regarding $_[0] vs. shift - the former tends to be faster, not slower?

Tom

Note also that @_ is alias to arguments given to the sub which means that it gives you not only read access to the argument, but also write access if it is a variable.

my $a = 2;
say $a;

sub change_arg_0
{
$_[0] = 1;
}

change_arg_0($a);
say $a;

Leave a comment

About vytas

user-pic I am proud Perl developer since 2014. twitter: https://twitter.com/vytasdauksa