Perl Module 3  Functions and Packages
by K. Yue, copyright 2000
September 13, 2000

User Defined Functions

sub function_name
{  statements  ...
} Example:

&hello;
do hello();

 Examples:

$mood = "great";
&show_mood;
#  Now mood is depressing.
sub show_mood
{  print "I feel $mood.\n";
   $mood = "depressing";
}

#  sub add from Llama.
sub add
{  local ($sum) = 0;
   foreach (@_)
   { $sum += $_;
   }
   $sum;
}

sub hello
{  my ($fname, $lname) = @_;
   print "Welcome to UHCL, $fname $lname!\n";
}

#    passing.pl
$a = 10;
$b = 20;

dummy1($a, $b);
print "\$a = $a\n";
print "\$b = $b\n";

$a = 10;
$b = 20;

dummy2($a, $b);
print "\$a = $a\n";
print "\$b = $b\n";

sub dummy1 {
    $_[0] = 50;
    $_[1] = 60;
}

sub dummy2 {
    my ($arg1, $arg2) = @_;
    $arg1 = 50;
    $arg2 = 60;
}

Exercise 1:

Write a Perl subroutine max, which takes a list of numbers and returns the largest value.

Exercise 2:

Write a function which accepts a yes-or-no question and prompt for user input: "yes" or "no".  Return 1 if users typed in 'y' or 'Y'.  Return 0 if 'n' or 'N'.  Otherwise, repeat the prompt until a valid response is typed in.

Exercise 3:

Write a Perl subroutine date to accept a string of date of format "mm/dd/yy" and return a string of date of format "month day, year".  For example, if the input is "09/17/96", the output is "September 17, 1996".

System-Defined Functions

Example:

The function splice(ARRAY, OFFSET, LENGTH, LIST) replaces ARRAY[OFFSET ..OFFSET+LENGTH-1} by LIST.  It returns the replaced substring.

#!/opt/gnu/bin/perl
# Alternate solution for randomly printing strings.
srand;
@list = <STDIN>;
while (@list)
{  $string = splice(@list, rand @list, 1);
   print $string;
}

Packages

Example: (partially from Camel).

# A priority queue.
sub add_entry
{  package Priority_Queue;
   local ($priority, $message) = @_;
   for ($i=0; $i <= $#queue; $i++)
   {  last if $priority > $queue[$i];
   }
   splice(@queue, $i, 0, "$priority:$message");
}

sub next_entry
{  package Priority_Queue;
   return () unless @queue;
   split(/:/, shift(@queue), 2);
}

#  Print all messages from 'main'.
foreach (@Priority_Queue'queue)
{  print s/.*://;
}

Modules

use cgi-lib.pm;

References

Symbolic References

*pp = *qq;
#   $pp is now an alias of $qq.
#   @pp is now an alias of @qq.
#   %pp is now an alias of %qq.
*rr = *$ss;
#   Only $rr is an alias $ss.
#   @rr is not an alias of @ss. Example: What are the output of the following two Perl programs?

#!/opt/gnu/bin/perl
@num = (2, 5, 8);
print "The numbers: @num.\n";
&process_num(@num);
print "The numbers are now: @num.\n";

sub process_num {
   print "The last number is ", pop(@_), ".  It is removed.\n";
   foreach (@_) {
      $_++;
   }
}

#!/opt/gnu/bin/perl
@num = (2, 5, 8);
print "The numbers: @num.\n";
&process_num(*num);
print "The numbers are now: @num.\n";

sub process_num {
   local(*para) = @_;
   print "The number of parameter passed: " , scalar(@_), ".\n";
   print "The last number is ", pop(@para), ".  It is removed.\n";
   foreach (@para) {
      $_++;
   }
}

Hard References

Examples:

$scalarref = \$m;
$arrayref = \@ARGV;
$hashref = \%ENV;
$coderef = \&handler;
$globref = \*STDOUT;
$reftoref = \$scalarref;
$constref=\1997.5;
$name="Bun Yue";

Example:

$q = 10;
$p = \$q;
print "\$p is ", $p, ".\n";
print "\$\$p is ", $$p, ".\n";

@nums = (1, 2, 3, 4);
$r = \@nums;
print "\$r is ", $r, ".\n";
print "\@\$r is ", @$r, ".\n";

The output looks like:

$p is SCALAR(0xb75e0c).
$$p is 10.
$r is ARRAY(0xb75e9c).
@$r is 1234.

Example 2.2: redoing 1.1 using hard references.

#!/opt/gnu/bin/perl
@num = (2, 5, 8);
print "The numbers: @num.\n";
&process_num(\@num);
print "The numbers are now: @num.\n";

sub process_num {
   local($ref) = @_;
   print "The number of parameter passed: " , scalar(@_), ".\n";
   print "The last number is ", pop(@$ref), ".  It is removed.\n";
   foreach (@$ref) {
      $_++;
   }
}

Suggested Solutions To Module #3

1. For example,

sub max
{  local ($max) = pop(@_);
   foreach (@_)
   {  $max = $_ if $_ > $max;
   }
   $max;
}

2. For example,

sub yes_or_no
{  local($answer);
   for (;;)
   {  print "@_[0] [y/n].\n==> ";
      $answer = <STDIN>;
      return 1 if $answer =~ /^y/i;
      return 0 if $answer =~ /^n/i;
   }
}

3. For example,

sub date
{ local (@month) = ('January', 'February', 'March',
                    'April', 'May', 'June',
                    'July', 'August', 'September',
'October', 'November', 'December');
  local ($m, $d, $y) = split(/\//, (shift @_));
  return "$month[$m-1]" . " $d, 19$y";
}