In general, subroutines should receive data, process that data, and then output something. There are some exceptions. In void context, we have no output. In the case of information retrieval from a fixed source there may not be any input. An error logging routine might have input and output but no processing.

Good subroutines only affect and are affected by their own environment. If events exterior to the subroutine affect it, you have probably done something wrong. Here's an example of a poorly written subroutine. foo() is using $bar. $bar has not been passed to it. Remember that a well written subroutine has data passed to it. Good subroutines only affect and are affected by their own environment. Deleting the $bar variable outside this subroutine affects the subroutine.

  1. sub foo {
  2.     return $bar;
  3. }

How do we fix this? We first pass information into the subroutine and then return that information.

  1. sub foo {
  2.     my $bar = shift;
  3.     return $bar;
  4. }

Let's look at another example. This one is from an actual script written by a beginner and sent to a perl beginner email list.

  1. dateme() # call dateme function and store value in $process_date;
  3. sub dateme {
  4.     $process_date=localtime();   # call localtime funcion and store as scalar value
  5.     return  $process_date;       # return scalar value of the localtime function
  6. }

Here we are changing a variable in the exterior environment. We also return a value which is not used by the call.

How do we fix this? We eliminate the subroutine. :)

  1. $process_date = localtime();

Another solution would be to use this as a function. In perl a function is defined the same as a subroutine. We call it a function because it returns a value. So a function is just a particular type of subroutine.

  1. my $process_date = time_stamp();
  3. sub time_stamp {
  4.    return scalar localtime( $^T );
  5. }

$^T is the start time of the script. Using this gives us the same time stamp in each use.