Skip to content

Latest commit

 

History

History
144 lines (98 loc) · 4.67 KB

method_sub_equivalence.pod

File metadata and controls

144 lines (98 loc) · 4.67 KB

Method-Function Equivalence

Perl 5's object system is deliberately minimal (blessed_references). Because a class is a package, Perl itself makes no strong distinction between a function stored in a package and a method stored in a package. The same builtin, sub, expresses both. Documentation and the convention of treating the first parameter as $self can imply intent to readers of the code, but Perl itself will treat any function of the appropriate name it can find in an appropriate package as a method if you try to call it as a method.

Likewise, you can invoke a method as if it were a function--fully-qualified, exported, or as a reference--if you pass in your own invocant manually.

Both approaches have their problems; avoid them.

Caller-side

Suppose you have a class which contains several methods:

If you have an Order object $o, the following invocations of this method may seem equivalent:

Though in this simple case, they produce the same output, the latter violates the encapsulation of objects in subtle ways. It avoids method lookup altogether.

If $o were instead a subclass or allomorph (roles) of Order which overrode calculate_price(), calling the method as a function would produce the wrong behavior. Any change to the implementation of calculate_price(), such as a modification of inheritance or delegation through AUTOLOAD()--might break calling code.

Perl has one circumstance where this behavior may seem necessary. If you force method resolution without dispatch, how do you invoke the resulting method reference?

There are two possibilities. The first is to discard the return value of the can() method:

The second is to use the reference itself with method invocation syntax:

When $meth_ref contains a function reference, Perl will invoke that reference with $o as the invocant. This works even under strictures, as it does when invoking a method with a scalar containing its name:

There is one small drawback in invoking a method by reference; if the structure of the program has changed between storing the reference and invoking the reference, the reference may no longer refer to the current, most appropriate method. If the Order class has changed such that Order::apply_discount is no longer the right method to call, the reference in $meth_ref will not have updated.

If you use this form of invocation, limit the scope of the references.

Callee-side

Because Perl 5 makes no distinction between functions and methods at the point of declaration and because it's possible (however inadvisable) to invoke a given function as a function or a method, it's possible to write a function callable as either.

The core CGI module is a prime offender. Its functions manually inspect @_ to determine whether the first argument is a likely invocant. If so, they ensure that any object state the function needs to access is available. If the first argument is not a likely invocant, the function must consult global data elsewhere.

As with all heuristics, there are corner cases. It's difficult to predict exactly which invocants are potentially valid for a given method, especially when considering that users can create their own subclasses. The documentation burden is also greater, given the need to explain the dichotomy of the code and the desire to avoid misuse. What happens when one part of the project uses the procedural interface and another uses the object interface?

Providing separate procedural and object interfaces to a library may be justifiable. Some designs make some techniques more useful than others. Conflating the two into a single API will create a maintenance burden. Avoid it.

POD ERRORS

Hey! The above document had some coding errors, which are explained below:

Around line 3:

A non-empty Z<>