-> is used to subscript the
referenced element as an array or a hash.
%hash = (a => 10,b => 20);
$x = \%hash;
print "$x->{a}\n";
@a = %{$x};
print "@a\n";
$x = \@a;
print "$x->[0], $x->[1]\n";
Procedural abstraction is the replacement of a sequence of
instructions by a name. You've seen this in Perl functions. The
sub declaration gives a name to a piece of code
that can then be used over and over without having to
know how it's implemented.
The other kind of abstraction you may not be familiar with is data abstraction, in which a collection of data objects is grouped together and thought of as a single entity. The formal notion of data abstraction is somewhat more complicated than this, but this concept is at its core.
Person. Imagine we already have such a class
and each person has three attributes (a name, age, and
list of friends). We would like to be able to manipulate
person objects as specified in this piece of code:
#create a new person
$me = Person->new();
#give the person a name
$me->name("Joe");
#give the person an age.
$me->age(43);
#print some facts about the person called $me.
print $me->name(), ": ", $me->age(), "\n";
That reference has been blessed, or associated with a class.
Person.pm. It would look something like this:
package Person;
use strict;
#
# new is the method used to construct a new object
#
sub new {
my $class = shift;
$class = ref($class) || $class;
my $self = {}; # The new object is represented by a hash
$self->{NAME} = undef;
$self->{AGE} = undef;
$self->{FRIENDS} = [];
bless ($self, $class); # This says the object $self belongs to the
# specified class.
return $self;
}
#
# methods (behaviors of the object)
# I'm writing these to be setters (set the value) if they get an argument
# or getters (get the value)
#
sub name {
my $self = shift;
if (@_) {
$self->{NAME} = shift;
}
return $self->{NAME};
}
sub age {
my $self = shift;
if (@_) {
$self->{AGE} = shift;
}
return $self->{AGE};
}
sub friends {
my $self = shift;
if (@_) {
@{ $self->{FRIENDS} } = @_;
}
return $self->{FRIENDS};
}
1; # this value is the result of require Person and must be a true value.
Person, namely the
Grouch class module. The program
test.pl shows how these can be used.
Notice that the Person class method
friends will set the FRIENDS element of the
hash to have a value that is the list of friends given (when
it's called with arguments), but the Grouch
friends method ignores its arguments. Therefore,
when you call friends on a Grouch
object, it doesn't add the list of friends to the object.
It ignores them.
my $class = shift;
$class = ref($class) || $class;
The ref function takes a reference as its argument
and if that reference is a blessed object, it will
return the name of the class to which it belongs. If the
object is not blessed, it will return undef.
If you call new with an object, then
$class gets set to the object. Then
ref of the object returns the class to which it
belongs, so $class = ref($class) || $class
just evaluates the first argument of || (since
it uses short circuit evaluation.
If you call new on a class like Person,
that is Person->new();, then the first argument
will be the bareword (or string) Person.
Calling ref on that string will yield
undef, so the second argument of ||
is evaluated, namely the class name.
Later on, when you bless self as follows:
bless ($self, $class)
It gets blessed into the class $class.
While it could be package global data, it is then available
to misuse from any other package. Instead, we prefer to
use lexically scoped my variables for representing
classwide data.
Thus, we might include the following code in the package:
my $Census = 0;
Person to handle keeping
census data correct?
Person ever
die?
One way objects die is by being garbage collected. Perl will
destroy objects it determines are no longer accessible to the
system. When such objects are destroyed, the unique method
DESTROY is called.
How could we modify our program so that it keeps an accurate census even in the face of deaths of objects?