While tidying up some code recently I was pondering the problems with the use of the _method_name() convention to indicate private methods in Perl.
Of course their are many alternative conventions that prevent the accidental overriding of methods in subclasses, for example:
package Foo; my $_private = sub { ... }; my _private = sub { ... }; sub foo { my $self = shift; # we can specify the full package name $self->Foo::_private(); # we can call as a subroutine _private($self); # we can use lexically scoped subs $self->$_private(); };
They also all have disadvantages of one sort or another, for example:
With the package name and subroutine calling methods we can prevent the method from being inherited by subclasses by putting it in a seperate package (see (tye)Re: Private Class Methods for an example). So we can do things like:
package Foo; sub Foo::private::method { ... }; sub foo { my $self = shift; $self->Foo::private::method { ... }; };
Which is nice, but we still have to repeat the Foo::private package every time we call the method - which for VeryLongPackageNames could be tedious.
A convenient shortcut to the private method space would be nice. Maybe something like:
sub Foo::MY::method { ... }; sub foo { my $self = shift; $self->MY::method(); };
This fits in quite nicely with SUPER:: and NEXT::.
This is actually pretty trivial to implement - just stick an AUTOLOAD in the MY package:
package MY; sub AUTOLOAD { my $self = shift; our $AUTOLOAD; my $method = caller() . "::$AUTOLOAD"; $self->$method(@_); };
and Bob's the parental sibling of your choice.
Unfortunately this adds an extra method call worth of overhead to every private method. Probably a bad move - Perl's method invocation is slow enough as it is.
It would also be nice to be able to do:
sub MY::method { ... };
rather than
sub MyLongPackageName::MY::method { ... };
Having to repeat MyLongPackageName for every private method definition is a pain.
Looks like a job for (and I don't say this very often because they're evil :-) a source filter.
package MY; use strict; use warnings; my $Imported_from; sub import { $Imported_from = caller }; use Filter::Simple; FILTER_ONLY code => sub { s/(\w+::)*MY::/${Imported_from}::MY::/gs }; 1;
Which will allow us to write code like this:
package Foo; use MY; sub new { bless {}, shift }; sub hello { my $self = shift; $self->MY::greet_world("hi"); }; sub MY::greet_world { my ($self, $greeting) = @_; print "$greeting world\n"; }; package Bar; use base qw(Foo); use MY; sub new { my $class = shift; $class->MY::greet_world(); return $class->SUPER::new(@_); }; sub MY::greet_world { print "A new Bar has entered the world\n"; };
Without the two private greet_world() methods of Foo and Bar interfering, and without any run-time overhead.
Neat.
Worth throwing at CPAN?
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: Private method variations
by TimToady (Parson) on Mar 01, 2004 at 05:52 UTC | |
by adrianh (Chancellor) on Mar 01, 2004 at 14:20 UTC | |
by TimToady (Parson) on Mar 01, 2004 at 17:34 UTC | |
by adrianh (Chancellor) on Mar 01, 2004 at 22:29 UTC | |
by TimToady (Parson) on Mar 02, 2004 at 00:36 UTC | |
| |
by stvn (Monsignor) on Mar 01, 2004 at 17:33 UTC | |
by adrianh (Chancellor) on Mar 01, 2004 at 21:38 UTC | |
by stvn (Monsignor) on Mar 01, 2004 at 21:57 UTC | |
| |
by adrianh (Chancellor) on Mar 01, 2004 at 08:22 UTC | |
Re: Private method variations
by dragonchild (Archbishop) on Mar 01, 2004 at 02:35 UTC | |
by adrianh (Chancellor) on Mar 01, 2004 at 08:58 UTC | |
by flyingmoose (Priest) on Mar 01, 2004 at 05:33 UTC | |
by stvn (Monsignor) on Mar 01, 2004 at 17:54 UTC | |
Re: Private method variations
by flyingmoose (Priest) on Mar 01, 2004 at 01:36 UTC | |
by adrianh (Chancellor) on Mar 01, 2004 at 08:39 UTC | |
by esskar (Deacon) on Mar 01, 2004 at 02:09 UTC | |
by flyingmoose (Priest) on Mar 01, 2004 at 05:28 UTC | |
Re: Private method variations
by hardburn (Abbot) on Mar 01, 2004 at 14:23 UTC | |
by adrianh (Chancellor) on Mar 01, 2004 at 14:40 UTC | |
by TimToady (Parson) on Mar 01, 2004 at 17:46 UTC | |
by adrianh (Chancellor) on Mar 01, 2004 at 22:11 UTC | |
by TimToady (Parson) on Mar 02, 2004 at 00:57 UTC | |
| |
by duff (Parson) on Mar 01, 2004 at 20:58 UTC | |
by TimToady (Parson) on Mar 02, 2004 at 00:46 UTC |