Object Oriented Perl (1)
- Introduction
- Executing Blocks
- Using Subroutine Libraries
- Working with References
- Perl Objects
Introduction
Object oriented programming in Perl consists in the
utilization of several features of the language: Perl's
capacity of parsing pieces of code at run time--while
executing a main program--, the capacity of using references
and non-linear arrays (also called matrices in other
languages), the usage of modules, packages, and classes. To
understand the nature of objects in Perl one must be fluent
in all these concepts. This is not strictly necessary to use
objects created by other programmer, but may aid in the
event of some trouble arousing if the trouble was not
foreseen by the creator.
I will review here how to store and execute pieces of code,
and how to use libraries of subroutines, which are rather
straightforward topics. Then I will delve into the more
advanced topics of using references, and building packages
and modules. With these elements at hand, you will be in
conditions to understand this definition that belongs to the
the Perl documentation--:
An object is simply a reference that happens to know
which class it belongs to. A class is simply a package
that happens to provide methods to deal with object
references. A method is simply a subroutine that expects
an object reference (or a package name, for class
methods) as the first argument.
Executing Blocks
A piece of Perl code can be stored into a string, or be
defined as a block using curly brackets. In either way, it
can be executed using the eval statement. Examples:
1. Evaluating an expression
$s = '$a = 1; $b = 2; print $a+$b';
eval( $s );
Note that we are using single quotes to avoid the
interpolation of variables. Had we used double quotes, the
"$" character should have been escaped using a
backslash.
The output of this program is:
3
2. Evaluating a block
eval { $a = 1; $b = 2; print $a+$b };
The output of this program is:
3
Any variable setting, or subroutine and format definitions,
remain after the execution. The value returned is the value
of the last expression evaluated, but a return
statement may be used. The evaluation is performed in scalar
or array context, depending on the context of the
eval statement.
If there is a syntax error or runtime error, or a die
statement is executed, an undefined value is returned by
eval, and $@ is set to the error message. If there was
no error, $@ is set to a null string. If no argument is
given, $_ is evaluated. The final semicolon, if any, may be
omitted.
# Using the error checking
$evstr = '$a = 1; $b = 2; $c = $a + $b';
eval( $evstr );
if ($@ eq '') {
print "Everything's OK";
}
else {
print "We have a problem: $@";
}
|
Example no. 1
A shorter form of error checking:
eval { $answer = $a / $b; };
warn $@ if $@;
print "$answer\n";
|
A run-time error can be masked. In the following case, the
expression is not compiled.
eval '$answer ='; # sets $@ but doesn't stop the program
if ($@) { print "There was an error\n"; }
|
However, a block may produce a compile-time error. In this
case, the program is not executed because it fails in
compilation.
eval { $answer = };
Using Subroutine Libraries
Before explaining the use of libraries, I will review some
fundamental concepts about subroutines. Like many languages,
Perl provides for user-defined subroutines, also called
functions. These may be located anywhere in the main
program, loaded in from other files via the do,
require, or use statements, or even generated on
the fly using eval or anonymous subroutines. You can
even call a function indirectly using a variable containing
its name or a code reference to it.
All functions are passed as parameters one single flat list
of scalars, and all functions likewise return to their
caller one single flat list of scalars. Any arrays or hashes
in these call and return lists will collapse, losing their
identities--but you may always use pass-by-reference instead
to avoid this.
Any arguments passed to the routine come in as the array @_.
Thus if you called a function with two arguments, those
would be stored in $_[0] and $_[1]. The array @_ is a local
array, but its elements are aliases for the actual scalar
parameters. In particular, if an element $_[0] is updated,
the corresponding argument is updated (or an error occurs if
it is not updatable).
# Passing parameters to a function
$a = 1;
$b = 2;
SumAplusB( $a, $b);
sub SumAplusB
{
print $_[0]+$_[1];
}
|
Example no. 2
The output of this program is:
3
The return value of the subroutine is the value of the last
expression evaluated. Alternatively, a return
statement may be used to exit the subroutine, optionally
specifying the returned value, which will be evaluated in
the appropriate context (list, scalar, or void) depending on
the context of the subroutine call. If you specify no return
value, the subroutine will return an empty list in a list
context, an undefined value in a scalar context, or nothing
in a void context. If you return one or more arrays and/or
hashes, these will be flattened together into one large
indistinguishable list.
# Returning the last expression evaluated
$a = 1;
$b = 2;
print SumAplusB( $a, $b);
sub SumAplusB
{
$_[0]+$_[1];
}
|
Example no. 3
The output of this program is:
3
# Returning several values
@list = Limits(5);
print "Limits are: $list[0], $list[1]";
sub Limits
{
my($pred, $succ);
$pred = $_[0] - 1;
$succ = $_[0] + 1;
return $pred, $succ;
}
|
Example no. 4
The output of this program is:
Limits are: 4, 6
Perl does not have named formal parameters, but in practice
all you do is to assign the parameter array to a my()
list. All variables in such a list are private to the
subroutine. Remember that any variables you use in the
function that aren't declared private are global variables.
# The subroutine is called with an array as argument.
$mon=1; $tue=3; $wed=5; $thu=7; $fri=9;
$bestday = max($mon,$tue,$wed,$thu,$fri);
print "The maximum is $bestday";
sub max {
# $max receives the first element of the array
my $max = shift(@_);
# the array is searched for any element greater
# than the current maximum
foreach $foo (@_) {
$max = $foo if $max < $foo;
}
return $max;
}
|
Example no. 5
The output of this program is:
The maximum is 9
Use array assignment to a local list to name your formal
arguments:
%Foo = {}; # declare a global hash
# fill two pairs of the hash
maybeset('Monroe','Marylin');
print $Foo{'Monroe'},"\n";
maybeset('Hepburn','Katherine');
print $Foo{'Hepburn'},"\n";
#
# this subroutine receives two arguments and
# assigns them to a hash pair unless there is
# already a pair with the same key
sub maybeset {
my($key, $value) = @_;
$Foo{$key} = $value unless $Foo{$key};
}
|
Inclusion of Subroutine Libraries
The easiest way is using the do statement.
do EXPR
EXPR is a string expresion that contains the name of a file.
This file is read and its contents evaluated as if using the
eval statement. If the file contains any subroutine,
the subroutine is added to the program. Otherwise, any
statement contained in the file is executed as if it were in
the program.
Let us suppose we have the following file, named
"sublib.pl".
# this statement is executed
$c = 4;
# this subroutine is included
sub suma2b {
my ($arg1, $arg2) = @_;
return $arg1 + $arg2;
} |
It can be called in this way.
# This program includes a subroutine in a separate file
using
# the 'do' statement. Subroutine libraries can be built in
this
# way.
do 'sublib.pl';
# The variable 'c' was created in the file 'sublib.pl'.
# Beware that this is not a good programming practice.
print "An included variable: $c\n";
# The subroutine is called.
$a = 1;
$b = 2;
print "Result of the call: ";
print &suma2b( $a, $b ), "\n";
|
Example no. 6
To find the file, all the locations supplied in the -I
command line parameter are searched if the file isn't in the
current directory (see "The @INC array"). For example, if
you have all your libraries in a sub-directory named 'subs',
you could use this command.
>perl -I ./subs examp02.pl
The do statement reparse the library file every time
you call it, so it is not convenient to use it inside a
loop. The inclusion of library modules is better done with
the use and require statements, which also do
error checking and raise an exception if there's a problem.
Working with References
Creating references
References can be constructed in several ways. The simplest
one is by using the backslash operator on a variable,
subroutine, or value. (This works much like the & operator
in C.). Here are some examples:
$scalarref = \$foo;
$arrayref = \@ARGV;
$hashref = \%ENV;
A reference to an anonymous array can be constructed using
square brackets:
$arrayref = [1, 2, ['a', 'b', 'c']];
Here we have constructed a reference to an anonymous array
of three elements whose final element is itself a reference
to another anonymous array of three elements.
A reference to an anonymous hash can be constructed using
curly brackets (see "The Comma Operator"):
$hashref = {
'Adam' => 'Eve',
'Clyde' => 'Bonnie',
};
Anonymous hash and array constructors can be intermixed
freely to produce as complicated a structure as you want.
A reference to an anonymous subroutine can be constructed by
using sub without a subname:
$coderef = sub { print "Boink!\n" };
Using references
Where you would put an identifier as a part of a variable
name, you can replace the identifier with a simple scalar
variable containing a reference of the correct type:
$foo = "1075";
$scalarref = \$foo;
$arrayref = [1, 2, ['a', 'b', 'c']];
$hashref = { 'Adam' => 'Eve', 'Clyde' => 'Bonnie' };
$bar = $$scalarref; # assign by
reference
print $scalarref,"\n"; # prints pointer
value
print $bar,"\n"; # prints 1075
print $$arrayref[0],"\n"; # prints 1
print $$hashref{"Adam"},"\n"; # prints Eve
push(@$arrayref, $foo); # push into
reference
Where you would put an identifier as a part of a variable
name, you can replace the identifier with a BLOCK returning
a reference of the correct type. The block can consist of
the name of a variable containing a reference and surrounded
with curly braces.
$bar = ${$scalarref};
${$arrayref}[0] = "January";
${$hashref}{"KEY"} = "VALUE";
push(@{$arrayref}, $filename);
As a form of syntactic sugar, the examples for this second
method may be written as (see "The arrow operator"):
$arrayref->[0] = "January"; # Array element
$hashref->{"KEY"} = "VALUE"; # Hash element
$coderef->(1,2,3); # Subroutine call
Briefly, references are rather like pointers that know what
they point to. This means that when you have something which
looks to you like a two-or-more-dimensional array and/or
hash, what is really going on is that the base type is
merely a one-dimensional entity that contains references to
the next level. It's just that you can use it as though it
were a two-dimensional one.
$list[7][12] # array of arrays
$list[7]{string} # array of hashes
$hash{string}[7] # hash of arrays
$hash{string}{'another string'} # hash of hashes
Perl objects
Perl objects are references to a special kind of array that
is
associated with a certain package (Perl's equivalent of a
class). This
association is made using the bless statement and so
objects
are called "blessed references." An object knows to which
package
(class) it belongs. Objects are created using routines
called
"constructors" that use the bless statement and
return the new
object. Constructors are customarily named new(), but
they may
have any name.
In the next example, I create an object "puppy" that belongs
to the
class "Doggie".
$puppy = Create Doggie (Tail => 'short', Ears => 'long');
# What class is puppy? (See the 'ref' function)
print ref $puppy,"\n"; # prints Doggie
print $puppy->{'Tail'}; # prints short
package Doggie;
sub Create {
my ($classname,$tail,$tail_value,$ears,$ears_value) =
@_;
# first declare an array
$foo = {};
# assign properties
$$foo{$tail} = $tail_value;
$$foo{$ears} = $ears_value;
# the bless statement tells the object referenced by
$foo
# that now it belongs to the package Doggie
bless($foo, $classname);
# return a reference to the object
return $foo;
# it could also be written
# return bless($foo, $classname);
# or just
# bless($foo, $classname);
}
|
Previous | Contents | Next
|