Perl Module 3  Functions, References and Packages
K. Yue, copyright 2001
September 19, 2001

User-Defined Functions

sub function_name
{  statements  ...
}

Example:

hello();
&hello;
do hello();

 Examples:

$mood = "great";
&show_mood;
# Now mood is depressing.
# Although global variables can be used,
# it is not a good style
sub show_mood
{  print "I feel $mood.\n";
   $mood = "depressing";
}

#  sum all arguments
sub sum
{  myl ($sum) = 0;
   foreach (@_)
   { $sum += $_;
   }
   $sum;
}

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

 

Illustrating argument passing mechanism:

#    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".

2. 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
# Randomly printing strings from STDIN.
srand;
@list = <STDIN>;
while (@list)
{  $string = splice(@list, rand @list, 1);
   print $string;
}

3. 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/.*://;
}

4. Modules

use CGI;
use LWP::Simple;

5. References

Symbolic References

This subsection can be skipped for beginners.

*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.

Using hard references to simulate true pass by reference.

#!/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
{  my $max = pop(@_);
   foreach (@_)
   {  $max = $_ if $_ > $max;
   }
   $max;
}

2. For example,

sub yes_or_no
{  my ($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
{ my (@month) = ('January', 'February', 'March',
                    'April', 'May', 'June',
                    'July', 'August', 'September',
                    'October', 'November', 'December');
  my ($m, $d, $y) = split(/\//, (shift @_));
  return "$month[$m-1]" . " $d, 20$y";
}