When writing a Perl module, do I have to specifica

2019-06-27 18:00发布

问题:

I'm writing a module that has several methods. Let's consider this :

package MyPackage;
sub new {
 ...
}

sub do_your_job {
 ...
}
1;

What is to stop someone calling do_your_job like MyPackage->do_your_job instead of $obj->do_your_job ? Do I need to check in every method that I'm receiving a reference as the first argument?

回答1:

No. If your module features only the most minimal documentation, it should be clear from that that do_your_job is a method that needs to be called on an object. If someone wants to call that in some other way, it's his fault.

Of course, you could check whether the first parameter to your method is a blessed object. But this has at least two drawbacks: You lose a little bit of performance and you clutter your methods with code that really doesn't do anything promised by the method's name.



回答2:

No, you don't need to check; you can just document that it's an object method and trust callers to use it as such. But if you feel that's insufficient, you certainly can check.

Same thing applies to arguments other than the method-call implicit object/class argument. You might have a parameter that's supposed to be an array ref, or a positive integer less than 10, or an object of some given type, or just about anything else. One path is to assume callers follow the documentation; the other is to trust nothing.



回答3:

The short answers in theory are "Nothing" and "That's not a bad idea."

In practice however, the documentation is what solves these problems. There's a common courtesy in the Perl community that instructs developers to only use modules in the manner which they have been documented.

Perl Modules come with no guarantee that the internals will never change. So an implicit agreement is that developers will not dig into the internals of a module/class unless they are implementing that module/class.



回答4:

As others have said, document what your module does and trust the user. However, it is worth thinking about the philosophical difference between a call on a class and a call on an object. If your Perl module provides a way of creating objects, many of the methods in that class are likely to rely on data specific to an individual object. This is probably the most common way of calling methods: once you have an object, you simply do $object->method(…). However, it is likely that some class methods are general and do not need data from a specific object. These are often called using the package name, and this is most commonly seen in calling a new() method, such as LWP::UserAgent->new().

Conveniently, Perl allows you to treat these two cases in the same way, using something like my $self = shift; at the beginning of the method: if the method is called on an object, $self gets the value of the object reference, if called on the class, $self gets the package name.

Even if the method is called on a class, so $self contains the package name, you can still call other methods on this package in the same way by doing $self->method(…). This is then compatible with calling the original method on a specific object, so everything holds together.

As just one example, the Perl Math::BigInt package includes quite a lot of methods, some of which are designed to be called on the package (class) itself (e.g. new()), some of which are to be called on individual objects (e.g. round()), and some on either (e.g. accuracy()).

The moral: it should be up to the functionality of the method as to whether it is capable of sensible meaning. It's reasonable to assume that the any method is being called with the expectation that it will do what you advertise it to. However, don't require a method call to be on an object when it might make sense for that method to be called on the class itself.



回答5:

You don't have to check the referent of a method call. However, based on what your specific application needs, you may want to:

 sub some_method {
      my( $class ) = @_;
      croak( "This is a class method only" ) if ref $class;
      ...
      }

Although I tend to not care so much, you might want to check that you have an instance before you try dereferencing something:

 sub some_instance_method {
      my( $self ) = @_;
      croak( "This is an instance method only" ) unless ref $self;

      $self->{some_attr};
      }

I tend to assume that the higher level will call it as I've documented it, though.



回答6:

Use Moose and forget about the plumbing.



标签: perl oop