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.

True laziness is hard work

In reply to Not quite an OO tutorial by GrandFather

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.