I put the following code sample on my scratch pad to encourage Lady_Aleena to investigate object oriented Perl. To my surprise it seems to be working (LA took notice ;) ). To my further surprise others have noticed and seem to like it so I captured the code here to give it a little more permanence and to provide a better forum for discussion than the CB.
I've split the code into a module and a script (although the original sample had all the code in the script) as a sop toward the convention of placing library code in modules. First the module code (placed in a file named RandomThings.pm):
use strict; use warnings; package RandThing; use overload '""' => '_asStr'; sub new { my ($class, @values) = @_; my $self = bless {values => \@values}, $class; $self->genValue (); return $self; } sub _asStr { my ($self) = @_; return $self->{value}; } sub genValue { my ($self) = @_; $self->{value} = $self->{values}[rand @{$self->{values}}]; return $self->{value}; } package RandDayPart; use parent -norequire, 'RandThing'; sub new { my ($class) = @_; my @values = qw(morning evening afternoon night); return $class->SUPER::new (@values); } package RandLight; use parent -norequire, 'RandThing'; sub new { my ($class) = @_; my @values = qw(bright dark gloomy dazzling); return $class->SUPER::new (@values); } package RandWeather; use parent -norequire, 'RandThing'; sub new { my ($class) = @_; my @values = qw(stormy windy rainy calm); return $class->SUPER::new (@values); } 1;
and the sample script:
use strict; use warnings; use RandomThings; my $dp = RandDayPart->new (); my $lt = RandLight->new (); my $wt = RandWeather->new (); my $tense = RandThing->new ('was', 'is', 'will be'); print "It $tense a $lt and $wt $dp.\n"; $dp->genValue (); print "It $tense a $lt and $wt $dp.\n";
which when run prints stuff like:
It was a bright and rainy morning. It was a bright and rainy evening.
First off, try to ignore the overload stuff (use overload and _asStr) which is really there as a cute way to avoid a bunch of method calls and concatenation operators when composing strings (and if that doesn't make sense yet just let your eyes glaze over and ignore it).
Ok, so look at the code between package RandThing and package RandDayPart. That is the code for the RandThing base class. sub new is the 'constructor'. It is used to create a RandThing (or derived class) 'object'. You can see how it is used in the my $tense = RandThing->new ('was', 'is', 'will be'); line in the sample script. The magic is in the bless which takes a reference (in this case a hash reference) and ties it to a variable using some magic string.
The magic kicks in when you 'call a member function' using code like $self->genValue ();. The blessed magic finds the genValue sub in the RandThing package and calls it passing $self as the first parameter. Notice that genValue creates a local variable $self and set it to the first parameter passed to the sub. We can now use $self in the sub to access the data referenced in the bless that created the object (look a sub genValue to see what I mean).
Ok, so far so good, but a lot of work for no apparent gain eh (still ignoring the overload stuff remember)?
In this example the good stuff becomes evident when we need to add a few different types of random thing. Really what we want is to have a few RandThingXXX types which provide their own lists of values. There are of course many ways to achieve that of course and, as with most fairly trivial examples, this probably isn't the best way. However ...
Take a look at the code following package RandDayPart. Note that there are a number of rather similar looking blocks, each prefixed by a package line. Note too that each block has a use parent line and a new sub, but nothing else.
The use parent makes the current package a 'sub-class' of the parent ('base') class. That means that if the bless magic can't find a 'member function' in the current package it will look in the parent package (and so on up if required). This stuff is 'inheritance' and is what lets us write all those packages that just have a constructor in them, but which still do useful stuff. Most of the real work gets done in the base class.
Note that the derived class constructors (new subs in RandDayPart etc.) use SUPER to call new in the parent package. The actual object is created in RandThing using values passed in by the derived class constructors.
Now, that's probably not anywhere near enough explaination yet, but I'm going to let the dust settle a little at this point and see who has questions or comments.
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: Not quite an OO tutorial
by lostjimmy (Chaplain) on Feb 23, 2011 at 16:00 UTC | |
by GrandFather (Saint) on Feb 23, 2011 at 19:35 UTC | |
Re: Not quite an OO tutorial
by gnosti (Chaplain) on Feb 24, 2011 at 05:50 UTC | |
by Lady_Aleena (Priest) on Feb 24, 2011 at 06:21 UTC | |
by james2vegas (Chaplain) on Feb 24, 2011 at 06:37 UTC | |
by Lady_Aleena (Priest) on Feb 24, 2011 at 07:20 UTC | |
by RedElk (Hermit) on Feb 24, 2011 at 18:44 UTC | |
by Anonymous Monk on Feb 24, 2011 at 09:08 UTC | |
by Lady_Aleena (Priest) on Feb 26, 2011 at 20:01 UTC | |
by stvn (Monsignor) on Feb 24, 2011 at 15:57 UTC | |
Re: Not quite an OO tutorial
by Lady_Aleena (Priest) on Feb 27, 2011 at 08:26 UTC | |
by GrandFather (Saint) on Feb 27, 2011 at 09:32 UTC |