convenientstore has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to learn basics of object oriented side in perl so that i can actually use some modules from cpan.org.
I went through few books on OO subject in perl but I find the terms and explanation difficult to follow (I am about little above beginner level in perl) on everything. While struggling to grasp the basics , I thought I ran into an excellent tutorial on below page
http://www.codeproject.com/perl/camel_poop.asp
and I was delighted as I was actually able to follow on very basics of the subject(for now, I just want to learn enough so that I can actually use OO modules in some scripts).. However, at the end of the article, I simply copy and paste the script and modules in hope to see the results but to my suprises, I get " cannot find the module Address.pm" Looking back at Person.pm, I see the use Address; statement. I am not sure if writer forgot to include a Address.pm or if this is standard modules that my perl is missing or?

PACKAGE PERSON
#class Person package Person; use strict; use Address; #Person class will contain an Address #constructor sub new { my ($class) = @_; my $self = { _firstName => undef, _lastName => undef, _ssn => undef, _address => undef }; bless $self, $class; return $self; } #accessor method for Person first name sub firstName { my ( $self, $firstName ) = @_; $self->{_firstName} = $firstName if defined($firstName); return $self->{_firstName}; } #accessor method for Person last name sub lastName { my ( $self, $lastName ) = @_; $self->{_lastName} = $lastName if defined($lastName); return $self->{_lastName}; } #accessor method for Person address sub address { my ( $self, $address ) = @_; $self->{_address} = $address if defined($address); return $self->{_address}; } #accessor method for Person social security number sub ssn { my ( $self, $ssn ) = @_; $self->{_ssn} = $ssn if defined($ssn); return $self->{_ssn}; } sub print { my ($self) = @_; #print Person info printf( "Name:%s %s\n\n", $self->firstName, $self->lastName ); } 1;
PACKAGE EMPLOYEE
# class Employee package Employee; use Person; use strict; our @ISA = qw(Person); # inherits from Person #constructor sub new { my ($class) = @_; #call the constructor of the parent class, Person. my $self = $class->SUPER::new(); $self->{_id} = undef; $self->{_title} = undef; bless $self, $class; return $self; } #accessor method for id sub id { my ( $self, $id ) = @_; $self->{_id} = $id if defined($id); return ( $self->{_id} ); } #accessor method for title sub title { my ( $self, $title ) = @_; $self->{_title} = $title if defined($title); return ( $self->{_title} ); } sub print { my ($self) = @_; # we will call the print method of the parent class $self->SUPER::print; $self->address->print; } 1;
MAIN PROGRAM
use strict; use warnings; use diagnostics; use Employee; #create Employee class instance my $khurt = eval { new Employee(); } or die ($@); #set object attributes $khurt->firstName('Khurt'); $khurt->lastName('Williams'); $khurt->id(1001); $khurt->title('Executive Director'); $khurt->address( new Address() ); $khurt->address->street('10 Anywhere Lane'); $khurt->address->city('Anytown'); $khurt->address->state('NJ'); $khurt->address->zip('12345'); #diplay Employee info $khurt->print();
Can't locate Address.pm in @INC (@INC contains: /script/perl/test2/mod +ules /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread-multi /usr/lib/ +perl5/site_perl/5.8.7/i386-linux-thread-multi /usr/lib/perl5/site_per +l/5.8.6/i386-linux-thread-multi /usr/lib/perl5/site_perl/5.8.5/i386-l +inux-thread-multi /usr/lib/perl5/site_perl/5.8.8 /usr/lib/perl5/site_ +perl/5.8.7 /usr/lib/perl5/site_perl/5.8.6 /usr/lib/perl5/site_perl/5. +8.5 /usr/lib/perl5/site_perl /usr/lib/perl5/vendor_perl/5.8.8/i386-li +nux-thread-multi /usr/lib/perl5/vendor_perl/5.8.7/i386-linux-thread-m +ulti /usr/lib/perl5/vendor_perl/5.8.6/i386-linux-thread-multi /usr/li +b/perl5/vendor_perl/5.8.5/i386-linux-thread-multi /usr/lib/perl5/vend +or_perl/5.8.8 /usr/lib/perl5/vendor_perl/5.8.7 /usr/lib/perl5/vendor_ +perl/5.8.6 /usr/lib/perl5/vendor_perl/5.8.5 /usr/lib/perl5/vendor_per +l /usr/lib/perl5/5.8.8/i386-linux-thread-multi /usr/lib/perl5/5.8.8 . +) at /script/perl/test2/modules/Person.pm line 4. BEGIN failed--compilation aborted at /script/perl/test2/modules/Person +.pm line 4. Compilation failed in require at /script/perl/test2/modules/Employee.p +m line 3. BEGIN failed--compilation aborted at /script/perl/test2/modules/Employ +ee.pm line 3. Compilation failed in require at ./first.obj line 6. BEGIN failed--compilation aborted at ./first.obj line 6 (#1) (F) You said to do (or require, or use) a file that couldn't be found. Perl looks for the file in all the locations mentioned in @ +INC, unless the file name included the full path to the file. Perhaps +you need to set the PERL5LIB or PERL5OPT environment variable to say w +here the extra library is, or maybe the script needs to add the library + name to @INC. Or maybe you just misspelled the name of the file. See perlfunc/require and lib. Uncaught exception from user code: Can't locate Address.pm in @INC (@INC contains: /script/perl/t +est2/modules /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread-multi / +usr/lib/perl5/site_perl/5.8.7/i386-linux-thread-multi /usr/lib/perl5/ +site_perl/5.8.6/i386-linux-thread-multi /usr/lib/perl5/site_perl/5.8. +5/i386-linux-thread-multi /usr/lib/perl5/site_perl/5.8.8 /usr/lib/per +l5/site_perl/5.8.7 /usr/lib/perl5/site_perl/5.8.6 /usr/lib/perl5/site +_perl/5.8.5 /usr/lib/perl5/site_perl /usr/lib/perl5/vendor_perl/5.8.8 +/i386-linux-thread-multi /usr/lib/perl5/vendor_perl/5.8.7/i386-linux- +thread-multi /usr/lib/perl5/vendor_perl/5.8.6/i386-linux-thread-multi + /usr/lib/perl5/vendor_perl/5.8.5/i386-linux-thread-multi /usr/lib/pe +rl5/vendor_perl/5.8.8 /usr/lib/perl5/vendor_perl/5.8.7 /usr/lib/perl5 +/vendor_perl/5.8.6 /usr/lib/perl5/vendor_perl/5.8.5 /usr/lib/perl5/ve +ndor_perl /usr/lib/perl5/5.8.8/i386-linux-thread-multi /usr/lib/perl5 +/5.8.8 .) at /script/perl/test2/modules/Person.pm line 4. BEGIN failed--compilation aborted at /script/perl/test2/modules/Person +.pm line 4. Compilation failed in require at /script/perl/test2/modules/Employee.p +m line 3. BEGIN failed--compilation aborted at /script/perl/test2/modules/Employ +ee.pm line 3. Compilation failed in require at ./first.obj line 6. BEGIN failed--compilation aborted at ./first.obj line 6. at ./first.obj line 6

Replies are listed 'Best First'.
Re: object oriented tutorial question
by jdporter (Paladin) on Sep 03, 2007 at 02:24 UTC

    Well, considering that that tutorial is posted on a site which bills iteself as "Your Visual Studio and .NET Resource" and doesn't even know how to spell Perl, I wouldn't expect too much. That said, that tutorial isn't too bad. But to answer your question, no, there is no standard module Address; the author simply didn't provide the source for it. It was left as "an excercise for the reader", presumably.

    Have you tried reading perlboot, the "poop" tutorial which ships with Perl itself? It's a pretty decent beginner intro. From there, proceed to perltoot and perlobj.

    A word spoken in Mind will reach its own level, in the objective world, by its own weight
      Also, this book:

      Object Oriented Perl

      by Damian Conway

      Is absolutely fabulous for OO in perl! It covers all the OO things you want to do, and how to do them the best possible way in perl.

      Brent Allsop

Re: object oriented tutorial question
by cdarke (Prior) on Sep 03, 2007 at 11:10 UTC
    Here is an Address.pm that works with your code:
    #class Address package Address; use strict; use warnings; #constructor sub new { my ($class) = @_; my $self = { _street => undef, _city => undef, _state => undef, _zip => undef }; bless $self, $class; return $self; } sub street { my ( $self, $street ) = @_; $self->{_street} = $street if defined($street); return $self->{_street}; } sub city { my ( $self, $city ) = @_; $self->{_city} = $city if defined($city); return $self->{_city}; } sub state { my ( $self, $state ) = @_; $self->{_state} = $state if defined($state); return $self->{_state}; } sub zip { my ( $self, $zip ) = @_; $self->{_zip} = $zip if defined($zip); return $self->{_zip}; } sub print { my ($self) = @_; print "Address: $self->{_street}\n". "$self->{_city}\n" . "$self->{_state}\n" . "$self->{_zip}\n\n" ; } 1;

      And here is an "inside-out" version of the same. The attributes have their own hashes that are not exposed to the outside world, so the nasty users can only access them by calling a method. The "object" that they see is the address of a 'my' variable, which is useless to them.
      #class Address using inside-out objects package Address; use Scalar::Util qw(refaddr); use strict; use warnings; my %street; my %city; my %state; my %zip; #constructor sub new { my ($class, $street, $city, $state, $zip) = @_; # Get any old (unique) reference my $self = bless \do{my $gash}, $class; my $key = refaddr $self; # Extract the address $street{$key} = $street; $city {$key} = $city; $state {$key} = $state; $zip {$key} = $zip; return $self; } sub street { my ( $self, $street ) = @_; my $key = refaddr $self; $street{$key} = $street if defined($street); return $street{$key}; } sub city { my ( $self, $city ) = @_; my $key = refaddr $self; $city{$key} = $city if defined($city); return $city{$key}; } sub state { my ( $self, $state ) = @_; my $key = refaddr $self; $state{$key} = $state if defined($state); return $state{$key}; } sub zip { my ( $self, $zip ) = @_; my $key = refaddr $self; $zip{$key} = $zip if defined($zip); return $zip{$key}; } sub print { my ($self) = @_; my $key = refaddr $self; print "Address: $street{$key}\n". "$city{$key}\n" . "$state{$key}\n" . "$zip{$key}\n\n" ; } 1;
        Your inside-out implementation is missing the obligatory destructor.
        sub DESTROY { my $id = refaddr shift; delete $_->{ $id} for \ ( %street, %city, %state, %zip); }

        I'd like to contrast an implementation of the Address class based on the Alter module. It is itself hash-based and thus closer to the original hash-based implementation than the inside-out variant, while still offering the black-box-inheritance properties. Essentially, the changes are that the ego() function is called on the object before each access to the object data.

        #class Address (Alter-based) package Address; use strict; use warnings; use Alter ego => {}; # alter ego is a hash #constructor sub new { my ($class) = @_; my $self = \ my $o; # the object proper (a scalar ref) %{ ego $self } = ( # set up the ego for this class _street => undef, _city => undef, _state => undef, _zip => undef ); bless $self, $class; return $self; } sub street { my ( $self, $street ) = @_; ego( $self)->{_street} = $street if defined($street); return ego( $self)->{_street}; } sub city { my ( $self, $city ) = @_; ego( $self)->{_city} = $city if defined($city); return ego( $self)->{_city}; } sub state { my ( $self, $state ) = @_; ego( $self)->{_state} = $state if defined($state); return ego( $self)->{_state}; } sub zip { my ( $self, $zip ) = @_; ego( $self)->{_zip} = $zip if defined($zip); return ego( $self)->{_zip}; } sub print { print "Address: $_->{_street}\n". "$_->{_city}\n" . "$_->{_state}\n" . "$_->{_zip}\n\n" for ego shift; } 1;
        Anno
Re: object oriented tutorial question
by blazar (Canon) on Sep 03, 2007 at 15:19 UTC
    I am trying to learn basics of object oriented side in perl so that i can actually use some modules from cpan.org.

    It's good that you want to learn how object orientation is done in Perl, but as a side note you don't have strictly to understand that to use even OO modules from CPAN since their public interface is documented anyway. You just have to get familiar with some bits of syntax, e.g. the arrow for calling methods.

Re: object oriented tutorial question
by FunkyMonk (Chancellor) on Sep 03, 2007 at 16:10 UTC
    I can't see any reference to Address other than use Address, so I think the program will work if you remove the use statement.