markcsmith has asked for the wisdom of the Perl Monks concerning the following question:
Monks,
This is probably a question resulting from a java-based
intro to oo design. I'm still working on the conversion to
perl, so please bear with me :)
Let's say there's code currently executing inside of a
private method in an instance of the Monkey class. I would
like this code to be able to access some instance fields,
but do not want to keep passing $self around from private
method to private method.
My (limited) understanding of perl tells this would be a
job for accessing the symbol table for this instance. I
could not find anything like this in the camel book (the
closest thing used a non-oo example w/ the %main:: symbol
table), so chances are I'm looking in the wrong places or
for the wrong thing.
Any help would be greatly appreciated.
Mark
Re: Instance field access from private methods
by perrin (Chancellor) on Oct 23, 2002 at 18:18 UTC
|
Plain and simple: if you don't pass $self, it is not a method. It can't be inherited, overriden, etc. You aren't supposed to pass $self explicitly; perl takes care of it for you.
Also, stay away from the symbol table. It's a dangerous place. | [reply] |
|
I'm not too sure. I wrote this (first time messing w/
iheritence w/ perl), and C2 obviously inherited the method
printWorld even though printWorld isn't passed the invocant
of printGoodBye.
C1.pm:
*******
package C1;
sub new {
my $class = shift;
my $self = {};
return bless $self, $class;
}
sub printGoodBye{ print "Goodbye @_ "; printWorld(); }
sub printWorld{ print "World\n @_"; }
1;
END {}
C2.pm
******
package C2;
use base ("C1");
sub new {
my $class = shift;
my $self = {};
return bless $self, $class;
}
sub printHi{ print "Hi\n"; }
1;
END {}
o.pl
****
#!/usr/bin/perl
use C2;
$bob = C2->new();
$bob->printGoodBye();
exit 0;
Let me know if I'm wrong, but this sure looks like it's
inheriting something w/o $self being passed to me.
Mark | [reply] [d/l] [select] |
|
Let me know if I'm wrong, but this sure looks like it's inheriting something w/o $self being passed to me.
But it *is* passed, actually $bob is passed as the first element of @_ which is seen in the output
Goodbye C2=HASH(0x177f054) World
So you would normally shift off the first element to a lexical variable often called $self to use the subroutine as a method in OO-style
sub printGoodBye {
my $self = shift;
print "Goodbye ";
$self->printWorld();
}
sub printWorld{
my $self = shift;
print "World\n ";
}
So inheritance is really in play here. I am also a newbie when it comes to perl-OO, so I watch this thread with keen interest.(++) | [reply] [d/l] [select] |
|
|
|
|
| [reply] |
Re: Instance field access from private methods
by robartes (Priest) on Oct 23, 2002 at 18:40 UTC
|
perrin is eminently right. Object Oriented Perl is based on three little rules, one of which states that methods are just subroutines which always receive a reference to the instance implementation (usually, but by no means always, a blessed hash) as their first argument. We might be misunderstanding what you are saying, but if you are passing $self (the ref to the instance) around yourself, something's wrong and you're not doing OO Perl.
And, again as perrin says, stay out of the symbol table if you don't know what you're doing - there be dragons there. Not that I know what I'm doing or have let that little fact stop me from messing around with the symbol table myself, but be warned that I have holes in my feet as a consequence.
A very good book (well, the book really) on Object Oriented Perl is, amazingly enough, Object Oriented Perl, by the_damian, aka Damian Conway.
One of the pieces of advice in this book is that it is a good idea that even your private methods use the class' public accessor methods to get at private instance attributes. That way, there's no frustating hunting through your code when you change the implementation of one of your attributes.
CU Robartes- | [reply] |
Re: Instance field access from private methods
by chromatic (Archbishop) on Oct 23, 2002 at 23:27 UTC
|
No one has yet explained why the symbol table won't help you. Most objects are stored in lexical variables, which aren't held in a symbol table. It's possible to store an object in the package's symbol table, but by the time you take into account multiple concurrent objects, you've gone to more trouble than its worth to do the same thing using an object invocant gives you for almost free. :)
| [reply] |
Re: Instance field access from private methods
by rr (Sexton) on Oct 24, 2002 at 16:25 UTC
|
This is very simple.
Perl will automagically pass the object as the first argument to the subroutine if you use one of the method invocation syntaxes.
When you say private method, what exactly do you mean btw? There is only one way that I know of to *enforce* private methods which is to make a lexical reference in the package to the subroutine. Once within a public method, the private method is visible and callable via method invocation.
Back to your question. When calling a private method from a public method, just call like:
sub public_method {
my $object = shift;
$object->private_method;
}
sub private_method {
my $object = shift;
...
}
Basically, unless you create a lexical variable that contains a CODE ref, there is no way to really create and enforce a private method that I know of. This is by design BTW. Perl wisdom says that you shouldn't need a shotgun to keep people out of your living room. Thus your private methods are just conventions based on name normally. Like sub __private_method {};
rr | [reply] [d/l] |
|
|