Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

in perl, is it bad practice to call multiple subroutines with default arguments?

I am learning perl and understand that it is a common and accepted practice to unpack subroutine arguments using shift. I also understand that it is common and acceptable practice to omit function arguments to use the default @_ array.

Considering these two things, if you call a subroutine without arguments, the @_ can (and will, if using shift) be changed. Does this mean that calling another subroutine with default arguments, or, in fact, using the @_ array after this, is considered bad practice? Consider this example:

sub total { # calculate sum of all arguments
    my $running_sum;
    # take arguments one by one and sum them together
    while (@_) {
       $running_sum += shift;
    }
    $running_sum;
}

sub avg { calculate the mean of given arguments
    if (@_ == 0) { return }
    my $sum = &total; # gets the correct answer, but changes @_
    $sum / @_ # causes division by zero, since @_ is now empty
}

My gut feeling tells me that using shift to unpack arguments would actually be bad practice, unless your subroutine is actually supposed to change the passed arguments, but I have read in multiple places, including Stack Overflow, that this is not a bad practice.

So the question is: if using shift is common practice, should I always assume the passed argument list could get changed, as a side-effect of the subroutine (like the &total subroutine in the quoted example)? Is there maybe a way to pass arguments by value, so I can be sure that the argument list does not get changed, so I could use it again (like in the &avg subroutine in the quoted text)?

like image 831
Mythoranium Avatar asked Dec 31 '12 10:12

Mythoranium


People also ask

Can we execute a subroutine without stack?

In practice, many languages do both, but in such a way that it's indistinguishable from always using the stack, because the stack is needed to handle recursion (and, these days, reentrancy), and executing a subroutine without using the stack is treated purely as an optimisation (often, "inlining").

How do you pass arguments in Perl subroutine?

You can pass various arguments to a Perl subroutine like you do in any other programming language and they can be accessed inside the function using the special array @_. Thus the first argument to the function is in [0],thesecondisin_[1], and so on.

What does @_ mean in Perl?

Using the Parameter Array (@_) Perl lets you pass any number of parameters to a function. The function decides which parameters to use and in what order.

What is subroutine in Perl explain with suitable example?

A Perl subroutine or function is a group of statements that together performs a task. You can divide up your code into separate subroutines. How you divide up your code among different subroutines is up to you, but logically the division usually is so each function performs a specific task.

What is a Perl function or subroutine?

A Perl function or subroutine is a group of statements that together perform a specific task. In every programming language user want to reuse the code. So the user puts the section of code in function or subroutine so that there will be no need to write code again and again.

How do I return a function in Perl without an argument?

There is even Perl::Critic policy that will check your code and point out every function that does not have an explicit return call at the end of the function declaration. If there is nothing to return just call return; without any argument.

What is the use of local variable in Perl?

Inside the function Hello, Perl! Outside the function Hello, World! The local is mostly used when the current value of a variable must be visible to called subroutines. A local just gives temporary values to global (meaning package) variables.

Does this still work in the newest versions of Perl?

This still works in the newest versions of Perl, but it is not recommended since it bypasses the subroutine prototypes. Let's have a look into the following example, which defines a simple function and then call it. Because Perl compiles your program before executing it, it doesn't matter where you declare your subroutine. Hello, World!


Video Answer


1 Answers

In general, shifting from the arguments is ok—using the & sigil to call functions isn't. (Except in some very specific situations you'll probably never encounter.)

Your code could be re-written, so that total doesn't shift from @_. Using a for-loop may even be more efficient.

sub total {
  my $total = 0;
   $total += $_ for @_;
  $total;
}

Or you could use the sum function from List::Util:

use List::Util qw(sum);

sub avg { @_ ? sum(@_) / @_ : 0 }

Using shift isn't that common, except for extracting $self in object oriented Perl. But as you always call your functions like foo( ... ), it doesn't matter if foo shifts or doesn't shift the argument array.
(The only thing worth noting about a function is whether it assigns to elements in @_, as these are aliases for the variables you gave as arguments. Assigning to elements in @_ is usually bad.)

Even if you can't change the implementation of total, calling the sub with an explicit argument list is safe, as the argument list is a copy of the array:

(a) &total — calls total with the identical @_, and overrides prototypes.
(b) total(@_) — calls total with a copy of @_.
(c) &total(@_) — calls total with a copy of @_, and overrides prototypes.

Form (b) is standard. Form (c) shouldn't be seen, except in very few cases for subs inside the same package where the sub has a prototype (and don't use prototypes), and they have to be overridden for some obscure reason. A testament to poor design. Form (a) is only sensible for tail calls (@_ = (...); goto &foo) or other forms of optimization (and premature optimization is the root of all evil).

like image 120
amon Avatar answered Oct 09 '22 02:10

amon