Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical

avoiding overwriting variables in an inherited class

by whatnext156 (Initiate)
on Apr 21, 2012 at 10:27 UTC ( #966337=perlquestion: print w/replies, xml ) Need Help??

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

Ok so I'm just tinkering with OO for the first time, and am bound to have got this totally wrong... BUT... the documentation I can find online on OO seems thin and confusing (where is the idiots guide??). I am struggling with the following and hope someone can enlighten me:

E.g. suppose I want to inherit from Email::Simple and create my own email type. Then I can add my own methods.

package FunnyEmail; use base Email::Simple; sub new{ my $class = shift; my $text = shift; # assume this gets passed my $self=Email::Simple->new($text); $self->{'JOKE'} = undef; # add my own variable bless $self,$class; return $self; }

(Have I even got this right?)

So now I can add methods which monkey about with $self->{'JOKE'}.

But my question is this: if $self refers to the hash created by Email::Simple when Email::Simple->new() was called then isn't there a danger $self->{'JOKE'} is already in use? How do I know I'm not messing up variables used in Email::Simple methods? Do I need browse the Email::Simple code to check the variable I am going to use is available, or am I protected somehow, or some other answer (possibly based on me having got the whole thing wrong from the outset!) ?

Thanks in advance for your help!

Replies are listed 'Best First'.
Re: avoiding overwriting variables in an inherited class
by JavaFan (Canon) on Apr 21, 2012 at 10:34 UTC
    That's a problem with Perl's absolute minimal OO. People have recognized this, and several solutions are available. For instance, using inside-out objects, you can do this with minimal code changes:
    package FunnyEmail; use base Email::Simple; use Hash::Util::FieldHash 'fieldhash'; ### Add this fieldhash my %JOKE; ### Add this sub new{ my $class = shift; my $text = shift; # assume this gets passed my $self=Email::Simple->new($text); $JOKE{$self} = undef; ### Change this bless $self,$class; return $self; }
    Now your 'JOKE' attribute is in a lexical variable, and not accessable outside of the lexical scope. So, it would not clash with whatever Email::Simple is using, nor will it clash with anything a subclass of FunnyEmail would be doing.

      Thank you for your replies .... sorry for taking a while to get back - I had some login problems as I have never posted to this site before! Hopefully now resolved.

      The fact this is an issue is a message that I do in fact have some kind of comprehension about the whole thing. Fantastic!!!

      After some initial difficulties (duh??) I have been reading more about inside-out objects and I have to agree with the poster that these must be the way forward.. alternatively using Moose? (your comments welcome) which negates the worry.

      in general i am surprised by Perl's OO as I am used to Perl being well thought out. I guess OO is always a subjective thing (higher level than the sequential stuff?). ie gives more flexibility but also an enormous number of ways of doing things?

        You could also use Moose, but (as someone who only does Moose when it's on my plate), Moose has always struck me more as a lifestyle than a solution to a problem; its community is not as cultish as some of the webframeworks, but they're on the edge.

        But hey, if it works for you, more power to you.

Re: avoiding overwriting variables in an inherited class
by choroba (Archbishop) on Apr 21, 2012 at 14:55 UTC
    Another approach is to add another level into the hash:
    package FunnyEmail; use strict; use warnings; use Email::Simple; sub new { my $class = shift; my $simple = Email::Simple->new(...); my $self = {simple => $simple}; bless $self, $class; }
    Now, you have to redirect all the methods of Email::Simple into the subhash:
    our $AUTOLOAD; sub AUTOLOAD { my $self = shift; my $simple = $self->{simple}; my $method = (split /::/, $AUTOLOAD)[-1]; if ($simple->can($method)) { $simple->$method(@_); } else { die "Cannot run $method\n"; } }
Re: avoiding overwriting variables in an inherited class
by tobyink (Canon) on Apr 22, 2012 at 08:29 UTC

    isn't there a danger $self->{'JOKE'} is already in use?

    Indeed. One way of avoiding this is to use your own package name in the hash key, to ensure a little more uniqueness:

    my $package = __PACKAGE__ . ':'; sub set_joke { my $self = shift; $self->{$package.'JOKE'} = shift; } sub get_joke { my $self = shift; return $self->{$package.'JOKE'}; } sub say_joke { my $self = shift; print $self->get_joke, "\n"; }

    This technique can only get you so far though - with some classes it's not enough, so the inside-out object technique explained by JavaFan is necessary.

    As an example, imagine an EmailHeaders class where each hash key represents an e-mail header (To, From, Subject, etc). You want to subclass it and store some additional information which is not an e-mail header. But any key you add to the hash will be interpreted as another e-mail header by the parent class. Here you really would need to use inside-out objects.

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://966337]
Front-paged by Corion
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (3)
As of 2021-04-19 01:17 GMT
Find Nodes?
    Voting Booth?

    No recent polls found