tags:

views:

297

answers:

4

I am writing Perl classes to remove redundancies from scripts and since Perl has a lot of ways to make classes I keep having trouble making the classes properly. So does anyone have a best practice example of a class?

The biggest question I have is if there should be no global variables in a module how do you use variables across sub() in a module? Like Java self->foo = 10;

Basically just give me a class written in Java or C# or even C++ and write the same in Perl. Also extra points for showing how to do private, protected and public class variables properly. Inheritance and interfaces would be helpful to I guess.

+13  A: 

Check out Moose, which is an extension of the Perl 5 object system.

The following will help you in learning Moose:

Alan Haggai Alavi
I realize this is a popular answer, however it did not actually show me how to make my own classes similar to other OOP languages.
kthakore
However, the post did point you to it.
Alan Haggai Alavi
You're right, instead he gave you links that show you how to do that. Why waste bytes copy/pasting from somewhere else when a link is much better.
mpeters
+8  A: 

a typical way of creating Perl objects is to 'bless' a hashref. The object instance can then store data against it's own set of hash keys.

package SampleObject;

use strict;
use warnings;

sub new {
    my ($class, %args) = @_;
    return bless { %args }, $class;
}

sub sample_method {
    my ($self) = @_;
    print $self->{sample_data};
}

and usage:

my $obj = SampleObject->new( sample_data => 'hello world',
                             more_data   => 'blah blah blah' );
$obj->sample_method();

Alternatively, accessor/mutator methods can be added (see Class::Accessor, Class::Accessor::Chained, etc for easy setting up of these) - these make it easier to validate data and add encapsulation (it's not enforced in Perl, you have to ensure your code doesn't touch go around an appropriate accessor/mutator and access the data in the blessed hashref directly).

plusplus
Seems the most elegant off the two answers.
kthakore
+4  A: 

Well, the Perl is easy, but I am rusty in the other languages, so I will update with them in a bit. Here is a plain Perl class:

#!/usr/bin/perl

package Person;

use strict;
use warnings;
use Carp;

sub new {
    my $class = shift;
    my $self  = { @_ };
    croak "bad arguments" unless defined $self->{firstname} and defined $self->{lastname}; 
    return bless $self, $class; #this is what makes a reference into an object
}

sub name {
    my $self = shift;
    return "$self->{firstname} $self->{lastname}";
}

#and here is some code that uses it
package main;

my $person = Person->new(firstname => "Chas.", lastname => "Owens");
print $person->name, "\n";

Here is the same class written using the new Moose style objects:

#!/usr/bin/perl

package Person;

use Moose; #does use strict; use warnings; for you

has firstname => ( is => 'rw', isa => 'Str', required => 1 );
has lastname  => ( is => 'rw', isa => 'Str', required => 1 );

sub name {
    my $self = shift;
    return $self->firstname . " " . $self->lastname;
}

#and here is some code that uses it
package main;

my $person = Person->new(firstname => "Chas.", lastname => "Owens");
print $person->name, "\n";

And MooseX::Declare removes the need for even more code and makes things look nice:

#!/usr/bin/perl

use MooseX::Declare;

class Person {
    has firstname => ( is => 'rw', isa => 'Str', required => 1 );
    has lastname  => ( is => 'rw', isa => 'Str', required => 1 );

    method name {
         return $self->firstname . " " . $self->lastname;
    }
}

#and here is some code that uses it
package main;

my $person = Person->new(firstname => "Chas.", lastname => "Owens");
print $person->name, "\n";

A quick note, These two class are the first two Moose classes I have ever written. And here is some very rusty C++ code (don't cut yourself on it or you will need a tetanus shot):

#include <stdio.h>
#include <string.h>

class Person {
    char* firstname;
    char* lastname;

    public:
    Person(char* first, char* last) {
     firstname = first;
     lastname  = last;
    }

    char* name(void) {
     int len = strlen(firstname) + strlen(lastname) + 1;
     char* name = new char[len];
     name[0] = '\0';
     strcat(name, firstname);
     strcat(name, " ");
     strcat(name, lastname);
     return name;
    }
};

int main(void) {
    Person* p    = new Person("Chas.", "Owens");
    char*   name = p->name();
    printf("%s\n", name);
    delete name;
    delete p;
    return 0;
}
Chas. Owens
Exactly what I wanted. You win 10 internet points Sir.
kthakore
+1  A: 

Besides Moose, which people have already mentioned...

If you are just talking about classes (so, not objects), you typically create class data with lexical variables scoped to the file and use one class per file. You create accessor methods to deal with them. There are various ways you can deal with that.

However, it sounds like you need to start with something like Intermediate Perl or Damian Conway's Object Oriented Perl. There's too much to explain for anyone to take the time to reproduce all of that in a Stackoverflow answer.

brian d foy
oooh nice books. Thx.
kthakore