Perl - OOP

perl

How can we generate a class file?

h2xs -X -n MG::Proxy

How can we specify inheritance?

Use the ISA array or the 'use base' directive:

use stricts;
@MG::Proxy::ISA = ("MG::Utils");

We can also specify inheritance using the 'use base' statement:

package Student::Busy;
use base 'Student';

All classes automatically inherit some basic functionality like isa and can from the UNIVERSAL class.

How can we define a constructor?

use stricts;
@MG::Proxy::ISA = ("MG::Utils");
sub new {
    my $this = shift;
    my $class = ref($this) || $this;
    my $self = $class->SUPER::new();
    bless  $self, $class;
    return $self;
}

In the above code we specify that MG::Proxy inherits from MG::Utils, and we define the constructor sub-routine "new".

A constructor 'new' with pseudo-private variables (by convention, private variable names start with underscore):

sub new {
    my $class = shift;
    my $hash = {
        _id => $_[1],
        _type => $_[2],
        _desc => $_[3]
    };
    bless $hash,$class;
    return $hash;
}
sub new {
    my $this = shift;
    my $class = ref($this) || $this;
    my $self = {};
    bless $self, $class;
    $self->initialize();
    return $self;
}

How can we instantiate an instance of a class?

my $proxy = MG::Proxy->new();

How can we define an instance method?

sub bump {
    my $self = shift;
    $self->{_count}++;
}

An instance method is simply a sub-routine that expects an object reference as the first parameter.

How can we define a private method?

sub _do_something {
    die("This method is private.") if (caller ne __PACKAGE__);
    my $self = shift;
    my $arg = shift;
}

By convention, the name of the private method should start with an underscore. However, notice the die method.

How can we define static variables?

package Something;
my $varname;
sub new {
    my $type = shift;
    my $self = {};
    bless $self, type;
}

Note the file scoped my variable.

What is a static method?

Static methods aren't called from an instance of an object, but instead directly from the package name. For example:

my $dbh = DBI->connect($dsn, $login, $pass);

How can we define a static method?

Static methods get the name of the calling class in their first parameter. Constructors are simply static methods:

package Student;

sub new {
    my($class, $name) = @_;
    # ...
}
sub list_all {
    my($class) = @_;
    # ...
}

package main;
use Student;
Student->list_all();

What are packages, classes, and objects?

Packages are classes. Objects are usually hash references bless-ed with a class name. Attributes are key/value pairs in that hash.

package Student;
sub new {
    my($class, $name) = @_;        # Class name is in the first parameter
    my $self = { name => $name };  # Anonymous hash reference holds instance attributes
    bless($self, $class);          # Say: $self is a $class
    return $self;
}

package main;
use Student;
my $amy = Student->new('Amy');
print $amy->{name}; # Accessing an attribute

Constructors are static methods that happen to return objects. Instead of Student->new('Amy') you may also write new Student('Amy'). Note however that the Perl parser relies on some funky heuristics to guess your true intentions and sometimes guesses wrong.

Can we define multiple constructors?

Yes. Because the new keyword is in no way magical in Perl, you may have as many constructor methods as you like and give them any name you like. For instance, you might want different constructors depending on whether you'd like to form an object from an existing record in a database, or create a new instance from scratch:

my $clara = Student->create();

How can we define an instance method?

Instance methods get a reference to the called object in their first parameter:

package Student;

sub work {
    my($self) = @_;
    print "$self is working\n";
}
sub sleep {
    my($self) = @_;
    print "$self is sleeping\n";
}

The reference to itself (this in Java) is never implicit in Perl.

Can instance method invoke static method?

Yes. Instance methods can call static methods using $self->static_method():

sub work {
    my($self) = @_;
    $self->list_all();
}

It is just like how instance method call another instance method.

How can we give a list of attributes that are allowed, and have Perl exit with an error if someone uses an unknown attribute?

Often you'd rather like to give a list of attributes that are allowed, and have Perl exit with an error if someone uses an unknown attribute. You do this using the fields pragma:

package Student;

use fields 'name',
           'registration',
           'grades';

sub new {
    my($class, $name) = @_;
    $self = fields::new($class);  # returns an empty "strict" object
    $self->{name} = $name;        # attributes get accessed as usual
    return $self;                 # $self is already blessed
}

package main;
use Student;

my $clara = Student->new('Clara');
$clara->{name} = 'WonderClara';  # works
$clara->{gobbledegook} = 'foo';  # blows up

What is the relationship between an object and a reference in Perl?

An object is simply a reference that happens to know which class it belongs to. Objects are blessed. References are not bless. Objects know which class they belong to. References do not know which class they belong to.

What is the relationship between a class and a package in Perl?

A class is simply a package that happens to provide methods to deal with object references.

What is the relationship between a method and a sub-routine in Perl?

A method is simply a sub-routine that expects an object reference (or a package name for class methods) as the first argument.

What is the relationship between a class and the UNIVERSAL class?

All classes implicitly inherit from class UNIVERSAL and all of its methods. If a missing method is found in one of the base classes, it is cached in the current class for efficiency. Changing the @ISA array or defining new subroutines invalidate the cache and cause Perl to do lookup again.

What is the relationship between a method and AUTOLOAD?

If neither the current class, it's based classes, nor UNIVERSAL class contains the requested method, these 3 places are searched again, this time looking for method named AUTOLOAD.

How can we invoke a method in the base class?

Use the SUPER keyword. If the child class overrode a method in the parent class, but still want to invoke the method in the parent class, the child method can invoke the overridden method in the parent class using the SUPER keyword:

sub display {
    my $self = shift;
    $self->SUPER::display();
}

How can we invoke a method if we do not know the name of the method ahead of time?

Some times we want to invoke a method but we do not know the name of the method ahead of time. In this situation, we can use the arrow form, replacing the method name with a simple scalar containing the name of the method:

$fred->$methodName(@args);
$fred->{$methodName}(@args);

How does Perl do garbage collection?

By reference count. When the last reference to an object goes away, the object is automatically destroyed. If you want to capture control just before the object is freed, you may define a DESTROY method in your class. It will automatically be called at appropriate moment, and you can do any extra clean up that you need. Perl passes a reference to the object being destroyed as the first (and only) argument to the DESTROY method. Beware that the reference is a read-only value, and cannot be modified by manipulating $_[0] within the DESTROY method. The object itself, namedly ${$_[0]}, @{$_[0]}, %{$_[0]} is still modifiable.

Objects contains within the current objects will be freed and destroyed automatically when the current object is freed, provided that no other references to them exist elsewhere.

What is the purpose of the DESTROY method?

By reference count. When the last reference to an object goes away, the object is automatically destroyed. If you want to capture control just before the object is freed, you may define a DESTROY method in your class. It will automatically be called at appropriate moment, and you can do any extra clean up that you need. Perl passes a reference to the object being destroyed as the first (and only) argument to the DESTROY method. Beware that the reference is a read-only value, and cannot be modified by manipulating $_[0] within the DESTROY method. The object itself, namedly ${$_[0]}, @{$_[0]}, %{$_[0]} is still modifiable.

How can we define a destructor method?

Define a method named DESTROY in your class.

Why would we want to re-bless a reference before the destructor function returns?

If you arrange to re-bless the reference before the destructor returns, Perl will again call the DESTROY method for the re-blessed object after the current one returns. This can be used for clean delegation of object destructions, or for ensuring that destructors in the base classes of your choosing get called.

Objects contains within the current objects will be freed and destroyed automatically when the current object is freed, provided that no other references to them exist elsewhere.

What are the guidelines for proper design?

  1. Always use the two-argument form of bless()
  2. Avoid direct access to global data
  3. Do not export anything by default

Does Perl support multiple inheritance?

Multiple inheritance (MI) can lead to complicated side effects. However, Perl does not forbid MI. MI is typically use to inherit class methods from Exporter, DynaLoader, AutoLoader, and SelfLoader. These classes exists only so that you may inherit their class method.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License