Object-Oriented Perl
#!/usr/bin/perl -w

####################  Demonstrating Object-Oriented Perl  ####################

use lib(".");   #  Look for Person/Employee modules in current directory.
use Person;     #  Capital letter prevents compiler warning!
use Employee;

$me  = Person->new("John Perry", "47", 10.00);

print $me->name()," ", $me->age(),"\n";
$you = $me->new();  #  Clone of myself!!

print $me->name()," ", $you->name(),"\n";
$me->name("Joe Doinck");  #  Change my name!
print $me->name()," ", $you->name(),"\n";  #  You and me now different??

$another = $me;
$me->name("Frank Discussion");  #  Change my name!
print $me->name()," ", $another->name(),"\n";  # Me and another now different??

#  Two new Employees
$john = Employee->new("John Doe", "5", 44444.44);
$mike = Employee->new("Mike Rophone", "3", 50000.00);

#  Use accessor functions to access John's attributes.
print $john->name()," ",$john->age()," ",$john->salary(),"\n";

$mike->name("Mike Hammer");  #  Change Mike's name.  See if change worked.
print $mike->name(),"\n";

#  See what staffsize is after first two Employees are hired!
print Employee->staffsize(),"\n";

undef $john;   #  Implicit call to DESTROY function in Employee. 
print Employee->staffsize(),"\n";   #  Did staff size get lowered?
##########################  Program Output Below ############################

John Perry 47            # Result of calls to $john->name() and $john->age().
John Perry John Perry    # $me->name() and $you->name() after $you = $me->new()
Joe Doinck John Perry    # Changed $me->{NAME}.  $you->{NAME} unchanged.
Frank Discussion Frank Discussion  #  Changed $me->{NAME} and therefore
                                   #  Changed $another->{NAME} because 
                                   #  $another = $me is NOT cloning!!!

Doe,John 5 44444.44      # Dump of $john fields (name, age, salary)
Hammer,Mike              # Changed name of $mike.  It worked!
2                        # Staff size after two new Employees
1                        # Staff size after Employee $john is undef'ed



package Person;    #  Person object constructors and methods.  Must be
                   #  in file Person.pm.  Note: No use Exporter or @EXPORT.
sub new
{
    my $type = shift;  #  Allows inheritance
    my ($self, $other) = ({}, {});  # Inits. are cosmetic -- not required.
    
    if (@_)  #  If I have args then assign object.
    {
        $self->{NAME} =  $_[0];
        $self->{AGE}  =  $_[1];
        bless $self, $type;   #  Type may not be Person due to inheritance!!
    }
    elsif (ref $type)  #  If I passed an object ref, clone existing object!
    {
        $other->{NAME} = $type->{NAME};  # $type is NOT a class name!
        $other->{AGE}  = $type->{AGE};   # It's an object *reference* !!
        bless $other, 'Person';
    }
    else  # Construct a new, unassigned object.  Assumes $type is a class name.
    {
        $self->{NAME} = $self->{AGE};
        bless $self, $type;
    }
    return ref($type) ? $other : $self;  #  If $type is a ref, pass back
                                         #  cloned object.  If $type is
                                         #  a class name, pass back constructed
                                         #  new object.
}

#  Accessor/mutator functions to get at object parts.
sub name 
{
     my $self = shift;

     #  If I gave an argument, assign new name to Person object.  Otherwise,
     #  simply tell user of this sub what the name is.
     if (@_) {$self->{NAME} = shift}
     return $self->{NAME};
}


sub age
{
     my $self = shift;

     if (@_) {$self->{AGE} = shift}
     return $self->{AGE}; 
}
1;  #  Required in object modules, too!
#######################  End of Person Object Module  ########################




package Employee;

@ISA = qw(Person);  #  @ISA contains base class names.

my $staffSize = 0;  #  A class (static) variable.

sub new
{
    my $type = shift;  
    my $self = {};
 
    $self = $type->SUPER::new($_[0], $_[1]);  #  Not $self->Person->new()!! 
    $self->{SALARY} = $_[2];
    $staffSize++;   #  Not $self->$staffSize++!  $StaffSize is a CLASS 
                    #  variable and NOT an object variable!
    return $self; 
}


#  Accessor/mutator functions to get at object parts.
#  Subs name and age inherited from Person object. 

sub name  # Overrides Person's name function.  Gives name as "last,first" 
{
     my $self = shift;

     if (@_) {$self->{NAME} = shift}
     else {$self->{NAME} = join(",", (split /\s+/, $self->{NAME})[1,0])} 
     return $self->{NAME}; 
}



sub salary   #  New method.  Not inherited from Person object. 
{
     my $self = shift;

     if (@_) {$self->{SALARY} = shift}
     return $self->{SALARY}; 
}


sub staffsize   #  Accesses class (static) variable.
{
     return $staffSize;
}


sub DESTROY     #  Staff size lowered when Employee object is destroyed.
{
     $staffSize--;
}
1;   #  Must always be here!!
#!/usr/bin/perl -w

###########  A timing package.

use lib(".");
use Timer;

$timer = Timer->new();
print $timer->elapsed(),"\n";

for ($i = 0; $i < 1000000; $i++) {}
print $timer->elapsed(),"\n";

for ($i = 0; $i < 500000; $i++) {}
print $timer->elapsed(),"\n";
##############################  Program Output  #########################
0
5
6
################################  Timer.pm  #############################

package Timer;

sub new
{
    my ($class) = shift;
    my ($self);

    $$self = time();
    return bless $self, $class;
}


sub elapsed
{
    my ($self) = shift;

    return time - $$self;
}
1;
##########################################################################

#!/usr/bin/perl -w

use lib(".");
use Array;     ##  A very simple array package.

@list = (1,2,3,4,5);
$aref = Array->new(@list);
print $aref->average();
################################  Program Output  ########################
3
###################################  Array.pm  ###########################
package Array;

sub new
{
    my ($type, @list) = @_;
    
    $self = [@list]; 
    return bless $self, $type;
}


sub average
{
    my ($self) = shift;
    my ($sum, $num);

    $sum = 0;
    foreach $num (@$self)
    {
        $sum += $num;
    }
    return $sum/@$self if @$self;
    return -1;
}
1;    
#########################################################################
#!/usr/bin/perl -w

use lib(".");
use Matrix;     #######   A Matrix package.

$ror = [[2,4,6], [7,6,5], [9,1,2], [8,4,3]];

$matrix = Matrix->new($ror);
$matrix->dump;

$copy = $matrix->new();
$copy->dump;

$matrix->ChangeRow(0, [1,3,5]);
$matrix->dump;

$copy->dump;

$trans = $matrix->transpose;
$trans->dump;
###############################  Program Output  #########################

2 4 6
7 6 5
9 1 2
8 4 3

2 4 6   #  The copy before the original was changed.
7 6 5
9 1 2
8 4 3

1 3 5   #  The original matrix with row 0 changed.
7 6 5
9 1 2
8 4 3

2 4 6   #  The copy AFTER the original was changed -- proof of deep copy!!
7 6 5
9 1 2
8 4 3

1 7 9 8   #  Transpose of the original matrix after row 0 was changed.
3 6 1 4
5 5 2 3

################################  Matrix.pm  #############################

package Matrix;

sub new
{
   my ($type) = shift;
   my ($self, $other);

   if (ref $type)
   {
       for ($i = 0; $i < @$type; $i++) {
            for ($j = 0; $j < @{$type->[$i]}; $j++)
            {
                 $other->[$i][$j] = $type->[$i][$j];
            }
       }
       return bless $other, 'Matrix';
   }
   elsif (@_)   #  Got a matrix reference.  Do a deep copy!
   {
       for ($i = 0; $i < @{$_[0]}; $i++) {
            for ($j = 0; $j < @{$_[0]->[$i]}; $j++)
            {
                 $self->[$i][$j] = $_[0]->[$i][$j];
            }
       }
       return bless $self, $type;
   }   
   else {return bless [], $type;}
}



sub dump
{
     my ($self) = shift;

     foreach $rowref (@$self)
     {
          print "@$rowref\n";
     }
     print "\n";
}



sub ChangeRow
{
    my ($self, $rownum, $rowref) = @_;

    $self->[$rownum] = [@$rowref];  #  Deep copy!
}



1;