Is it a good practice in Perl when instance methods call each other over a "$self" reference?
Should instance methods in Perl call each other like this:
package BlaBla;
sub foo {
my($self) = @_;
#开发者_如何学JAVAdo something awesome;
}
sub bar {
my($self) = @_;
foo();
}
Or like this:
package BlaBla;
sub foo {
my($self) = @_;
#do something awesome
}
sub bar {
my($self) = @_;
$self->foo();
}
Thank you all for your time.
Yes, you should include $self
- if you don't, polymorphism won't work because each method will look for all calls in its own package, even if they're overridden in a subclass. Worse, if the referenced method is inherited from a parent and not overridden in the current subclass, the program will die
because it doesn't exist in that package. And that's even if you do remember to try to fake out Perl's OO mechanism by passing $self
as the first parameter.
If foo() is a method that can be called from other places you should certainly always call it as a method, otherwise classes inheriting from you won't be able to override it, and you'll force your foo() to check if it's being called in a methody-way or in a functiony-way.
On the other hand, if foo() is just some helper code that a few of your methods use, and is quite specific to your implementation of the class, then you can call it directly, but should then really always call it directly, and might want to label it as a private function available to the class by prefixing its name with an underscore: _foo().
The first one won't work, assuming you use $self
somewhere in foo()
, because it's not getting any arguments passed. You could call foo($self)
, but you're almost certainly better off using actual method call syntax instead of throwing the OO features of Perl out the window and just treating foo()
as a function that happens to call its first parameter "$self
".
Yes, instance methods should call each other with $self
- otherwise, in some cases you'll need to check the args of the method and figure out whether it's being called on $self
or not, which will make your code messier for no reason.
Th first approach will not work as written.
sub bar {
my($self) = @_;
foo();
}
Here you are explicitly invoking foo
as a function with no arguments via that foo();
statement. This will construct an empty local @_
array. The first statement in foo
extracts $self
as the first element from this local @_
, so $self
is undefined with this mechanism.
You need to pass $self
as an argument to foo
. There are (at least) five ways to do this:
- Arrow notation: Invoke
foo
via$self->foo();
- Indirect notation: Invoke
foo
viafoo $self;
- Normal subroutine invocation: Invoke
foo
viafoo($self);
- Implied arguments: Invoke
foo
viafoo $self;
This option can only used iffoo
has been predeclared with a function prototype. - Don't construct that local
@_
array. Letfoo
piggyback onbar
's@_
array. Invokefoo
via&foo;
Note that there are no parentheses in this invocation.
Regarding option #5: It does exist. Don't use it. It will get you into trouble.
The difference between #2 and #4 become apparent when foo takes additional arguments. The indirect notation becomes (for example) foo $self 42;
while the implied form becomes foo $self, 42;
The indirect notation (option 2) is now strongly discouraged. Options 3 and 4 are also discouraged for use with methods.
That leaves option #1. Even though the arrow notation is just syntactic sugar, it means a lot to the reader. Use it.
精彩评论