DekGenius.com
[ Team LiB ] Previous Section Next Section

10.3 Indirect Object Notation

The arrow syntax used to invoke a method is sometimes called the direct object syntax because there's also the indirect object syntax, also known as the "only works sometimes" syntax, for reasons explained in a moment. When you write:

Class->class_method(@args);
$instance->instance_method(@other);

you can generally replace it with:

classmethod Class @args;
instancemethod $instance @other;

A typical use of this is with the new method, replacing:

my $obj = Some::Class->new(@constructor_params);

with:

my $obj = new Some::Class @constructor_params;

making the C++ people feel right at home. Of course, in Perl, there's nothing special about the name new, but at least the syntax is hauntingly familiar.

Why the previous "generally" caveat? Well, if the instance is something more complicated than a simple scalar variable:

$somehash->{$somekey}->[42]->instance_method(@parms);

then you can't just swap it around like:

instance_method $somehash->{$somekey}->[42] @parms;

because the only things acceptable to indirect object syntax are a bareword (e.g., a class name), a simple scalar variable, or braces denoting a block returning either a blessed reference or a classname.[6]

[6] Astute readers will note that these are the same rules as for an indirect filehandle syntax, from which indirect object syntax directly mirrors, as well as the rules for specifying a reference to be dereferenced.

This means you have to write it like so:

instance_method { $somehash->{$somekey}->[42] } @parms;

And that goes from simple to uglier in one step. There's another downside: ambiguous parsing. When we developed the classroom materials concerning indirect object references, we wrote:

my $cow = Cow->named("Bessie");
print name $cow, " eats.\n";

because we were thinking about the indirect object equivalents for:

my $cow = Cow->named("Bessie");
print $cow->name, " eats.\n";

However, the latter works; the former doesn't. We were getting no output. Finally, we enabled warnings (via -w on the command line)[7] and got this interesting series of messages:

[7] Using -w should be the first step when Perl does something you don't understand. Or maybe it should be the zeroth because you should normally have -w in effect whenever you're developing code.

Unquoted string "name" may clash with future reserved word at ./foo line 92.
Name "main::name" used only once: possible typo at ./foo line 92.
print(  ) on unopened filehandle name at ./foo line 92.

Ahh, so that line was being parsed as:

print name ($cow, " eats.\n");

In other words, print the list of items to the filehandle named name. That's clearly not what we wanted, so we had to add additional syntax to disambiguate the call.

This leads us to our next strong suggestion:

Use direct object syntax at all times, except perhaps for the constructor call.

That exception acknowledges that most people write new Class ... rather than Class->new(...) and that most of us are fine with that. However, there are circumstances in which even that can lead to ambiguity (e.g., when a subroutine named new has been seen, and the class name itself has not been seen as a package). When in doubt, ignore indirect object syntax. Your maintenance programmer will thank you.

    [ Team LiB ] Previous Section Next Section