开发者

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:

  1. Arrow notation: Invoke foo via $self->foo();
  2. Indirect notation: Invoke foo via foo $self;
  3. Normal subroutine invocation: Invoke foo via foo($self);
  4. Implied arguments: Invoke foo via foo $self; This option can only used if foo has been predeclared with a function prototype.
  5. Don't construct that local @_ array. Let foo piggyback on bar's @_ array. Invoke foo 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜