Object Oriented Perl (2)
- Operators for references
- Built-in functions for references
- Perl packages (classes)
- Perl modules
- A full example
Operators for references
The Arrow Operator
Just as in C and C++, "->" is a de-reference operator. If the right side is either a [...] or {...} subscript, then the left side must be a reference to an array or hash.
$arrayref->[0]
$hashref->{"KEY"}
Otherwise, the right side must be a method name, and the left side either be an object (a blessed reference) or a class name (that is, a package name).
$ob->method()
The Comma Operator
Binary "," is the comma operator. In a scalar context it evaluates its left argument, throws that value away, then evaluates its right argument and returns that value. This is just like C's comma operator. In a list context, it's just the list argument separator, and inserts both its arguments into the list.
The "=>" digraph is mostly just a synonym for the comma operator. It's useful for documenting arguments that come in pairs. It also forces any word to the left of it to be interpreted as a string.
$couples = { 'Adam' => 'Eve', 'Clyde' => 'Bonnie' };
Built-in functions for references
ref EXPR
ref
If EXPR is a reference, returns the type of the referenced element. Otherwise, returns FALSE. If EXPR is not specified, $_ will be used. Builtin types include:
REF
SCALAR
ARRAY
HASH
CODE
GLOB
If the referenced object has been blessed into a package, then that package name is returned instead. You can think of ref() as a typeof() operator.
if (ref($r) eq "HASH") {
print "r is a reference to a hash.\n";
}
if (!ref ($r) {
print "r is not a reference at all.\n";
}
Perl packages (classes)
The statement package NAMESPACE declares a subroutine as being in the given namespace. Typically it would be the first declaration in a file to be included by the require or use operator. All unqualified dynamic identifiers will be in this namespace. A package statement affects only dynamic variables--including those you've used local on--but not lexical variables, which are created with my.
There is no special class syntax in Perl, but a package may function as a class if it provides subroutines that function as methods. Perl implements a class using a package, but the presence of a package doesn't imply the presence of a class. A package is just a namespace. A class is a package that provides subroutines that can be used as methods. A method is just a subroutine that expects, as its first argument, either the name of a package, or a reference to something.
Each package can have a variable called @ISA, which governs method inheritance. If you try to call a method on an object or class, and that method is not found in that object's package, Perl then looks to @ISA for other packages to go looking through in search of the missing method.
There are two special subroutine definitions that can be used to take
care of package initialization and finalization. These are the BEGIN and END routines. The sub is optional for these routines.
A BEGIN subroutine is executed as soon as possible, that is, the moment it is completely defined, even before the rest of the containing file is parsed.
An END subroutine is executed as late as possible, that is, when the interpreter is being exited, even if it is exiting as a result of a die() function. Inside an END subroutine $? contains the value that the script is going to pass to exit(). You can modify $? to change the exit value of the script.
Here is an example not related with modules.
# Example of using BEGIN and END blocks.
# It prints all the lines in the input file that contain a file name
# ending in 'doc' or 'htm'. It also prints a count.
#
BEGIN {
$a = 0;
}
END {
print "Count=$a";
}
while (<>) {
if (/(\.htm|doc)$/i) { print; $a++; }
}
|
Perl modules
A module is just a set of related functions in a library file, i.e., a Perl package with the same name as the file. It may function as a class definition making its semantics available implicitly through method calls on the class and its objects.
In this case, it is a file that (by convention) provides a class of the same name (without the .pm).
All Perl module files have the extension ".pm". The 'use' statement assumes this so that you don't have to spell out "Module.pm" in quotes. Module names are capitalized by convention unless they are functioning as the compiler directives known as pragmas.
Perl modules are included into your program by saying
use Module;
or
use Module LIST;
The @INC array
The array @INC contains the list of places to look for Perl scripts to be evaluated by the do, require, or use constructs. It initially consists of the arguments to any -I command line switches, followed by the default Perl library, probably /usr/local/lib/perl, followed by ".", to represent the current directory. If you need to modify this at runtime, you should use the use lib pragma to get the machine-dependent library properly loaded also:
use lib '/mypath/libdir/';
use SomeMod;
The %INC hash
The hash %INC contains entries for each filename that has been included via do or require. The key is the filename you specified, and the value is the location of the file actually found. The require command uses this array to determine whether a given file has already been included.
The require statement
Demands that a library file be included if it has not already been included. The file is included via the do FILE mechanism. The file must return TRUE as the last statement to indicate successful execution of any initialization code, so it is customary to end such a file with "1;" unless you are sure it will return TRUE otherwise. But it is better just to put the "1;", in case you add more statements. The require statement assumes a ".pm" extension and replaces "::" with "/" in the filename.
The use statement
use Module;
is exactly equivalent to
BEGIN { require "Module.pm"; import Module; }
use Module LIST;
is exactly equivalent to
BEGIN { require "Module.pm"; import Module LIST; }
As a special case
use Module ();
is exactly equivalent to
BEGIN { require "Module.pm"; }
The BEGIN forces the require and import to happen at compile time. The require makes sure the module is loaded into memory if it hasn't been yet. The import is not a builtin--it's just an ordinary static method call into the "Module" package to tell the module to export the list of features into the current package. The module can implement its import method any way it likes, but it also can derive its import method via inheritance from the Exporter class that is defined in the Exporter module. This is done using the following definitions,
package ModuleName;
require Exporter;
@ISA = qw(Exporter);
Two arrays are used to specify what to export,
@EXPORT = qw(...); # symbols to export by default
@EXPORT_OK = qw(...); # symbols to export on request
The program calling the module can use:
use ModuleName; # to import default symbols
use ModuleName LIST; # to import listed symbols
use ModuleName (); # to import nothing
Pragmas (compiler directives) are also implemented this way. Some implemented pragmas are:
use integer;
use diagnostics;
use strict qw(subs vars refs);
There's a corresponding "no" command that unimports meanings imported by use, i.e., it calls unimport Module LIST instead of import.
no integer;
no strict 'refs';
A note on quote operators
While we usually think of quotes as literal values, in Perl they function as operators, providing various kinds of interpolating and pattern matching capabilities. Perl provides customary quote characters for these behaviors, but also provides a way for you to choose your quote character for any of them. In the following table, a {} represents any pair of delimiters you choose. Non-bracketing delimiters use the same character fore and aft, but the 4 sorts of brackets (round, angle, square, curly) will all nest.
Customary Generic Meaning Interpolates
'' q{} Literal no
"" qq{} Literal yes
`` qx{} Command yes
qw{} Word list no
// m{} Pattern match yes
s{}{} Substitution yes
tr{}{} Translation no
A full example
The following class provides functions to encode and decode strings
into the Base64 encoding specified in RFC 2045 (MIME, Multipurpose
Internet Mail Extensions). The Base64 encoding is designed to
represent arbitrary sequences of octets in a form that need not be
humanly readable. A 65-character subset ([A-Za-z0-9+/=]) of US-ASCII
is used, enabling 6 bits to be represented per printable character.
# strcode.pm
# This package implements a class, Strcode, that consists in a
# string which can be encoded and decoded
package Strcode;
use MIME::Base64;
# constructor
sub new {
# this constructor has two parameters: the first is the name
# of the class and the second is the initial value
# the object has two attributes: the decoded and the coded values
# first I create a reference to an anonymous empty hash array
my $foo = {};
shift; # I discard the first argument, i.e. the name of the class
# if after the shift there remains something, it must the value
if (@_) {
# create the first element from the argument - I use the element
# with the index 'ONESTR' of the anonymous array to store the
# initial value. The operator -> dereferences the array.
$foo->{ONESTR} = shift;
# The same applies to the second property.
$foo->{ENCODED} = ""; # create the second element as empty
# brand the object
bless($foo);
# return the reference to the anonymous array
return($foo);
}
else {
print "Syntax error\n";
exit;
}
}
# there are three methods - each receives a reference (object)
# and returns a string
sub encode {
my $foo = shift; # I get the first and only argument: the object
# I assign to a property the result of encoding the other
$foo->{ENCODED} = encode_base64($foo->{ONESTR},"");
# and return this same value.
return ($foo->{ENCODED});
}
sub decode {
# the reverse of the previous routine
my $foo = shift;
$foo->{ONESTR} = decode_base64($foo->{ENCODED});
return ($foo->{ONESTR});
}
sub deploy {
# simply shows the world the decoded (clear) value
my $foo = shift;
return ($foo->{ONESTR});
}
1;
|
Here is a Perl program that uses the class just defined.
# This program is an example of the use of the module Strcode.
# See: strcode.pm
use Strcode;
$onestr = Strcode->new("It was a beautiful september morning");
print "Original: ",$onestr->deploy,"\n";
print "Coded : ",$onestr->encode,"\n";
print "Decoded : ",$onestr->decode,"\n";
# this gives an error message as the argument is missing
$onestr = Strcode->new();
|
Previous | Contents | Next
|