12.3. Method InvocationIf you were to boil down all of object-oriented programming into one quintessential notion, it would be abstraction. It's the single underlying theme you'll find running through all those 10-dollar words that OO enthusiasts like to bandy about, like polymorphism and inheritance and encapsulation. We believe in those fancy words, but we'll address them from the practical viewpoint of what it means to invoke methods. Methods lie at the heart of the object system because they provide the abstraction layer needed to implement all these fancy terms. Instead of directly accessing a piece of data sitting in an object, you invoke an instance method. Instead of directly calling a subroutine in some package, you invoke a class method. By interposing this level of indirection between class use and class implementation, the program designer remains free to tinker with the internal workings of the class, with little risk of breaking programs that use it. Perl supports two different syntactic forms for invoking methods. One uses a familiar style you've already seen elsewhere in Perl, and the second is a form you may recognize from other programming languages. No matter which form of method invocation is used, the subroutine constituting the method is always passed an extra initial argument. If a class is used to invoke the method, that argument will be the name of the class. If an object is used to invoke the method, that argument will be the reference to the object. Whichever it is, we'll call it the method's invocant. For a class method, the invocant is the name of a package. For an instance method, the invocant is a reference that specifies an object. In other words, the invocant is whatever the method was invoked with. Some OO literature calls this the method's agent or its actor. Grammatically, the invocant is neither the subject of the action nor the receiver of that action. It's more like an indirect object, the beneficiary on whose behalf the action is performed--just like the word "me" in the command, "Forge me a sword!" Semantically, you can think of the invocant as either an invoker or an invokee, whichever fits better into your mental apparatus. We're not going to tell you how to think. (Well, not about that.) Most methods are invoked explicitly, but methods may also be invoked implicitly when triggered by object destructors, overloaded operators, or tied variables. Properly speaking, these are not regular subroutine calls, but rather method invocations automatically triggered by Perl on behalf of an object. Destructors are described later in this chapter, overloading is described in Chapter 13, "Overloading", and ties are described in Chapter 14, "Tied Variables". One difference between methods and regular subroutines is when their packages are resolved--that is, how early (or late) Perl decides which code should be executed for the method or subroutine. A subroutine's package is resolved during compilation, before your program begins to run.[3] In contrast, a method's package isn't resolved until it is actually invoked. (Prototypes are checked at compile time, which is why regular subroutines can use them but methods can't.)
The reason a method's package can't be resolved earlier is relatively straightforward: the package is determined by the class of the invocant, and the invocant isn't known until the method is actually invoked. At the heart of OO is this simple chain of logic: once the invocant is known, the invocant's class is known, and once the class is known, the class's inheritance is known, and once the class's inheritance is known, the actual subroutine to call is known. The logic of abstraction comes at a price. Because of the late resolution of methods, an object-oriented solution in Perl is likely to run slower than the corresponding non-OO solution. For some of the fancier techniques described later, it could be a lot slower. However, many common problems are solved not by working faster, but by working smarter. That's where OO shines. 12.3.1. Method Invocation Using the Arrow OperatorWe mentioned that there are two styles of method invocation. The first style for invoking a method looks like this: INVOCANT->METHOD(LIST) INVOCANT->METHOD For obvious reasons, this style is usually called the arrow form of invocation. (Do not confuse -> with =>, the "double-barreled" arrow used as a fancy comma.) Parentheses are required if there are any arguments. When executed, the invocation first locates the subroutine determined jointly by the class of the INVOCANT and the METHOD name, and then calls that subroutine, passing INVOCANT as its first argument. When INVOCANT is a reference, we say that METHOD is invoked as an instance method, and when INVOCANT is a package name, we say that METHOD is invoked as a class method. There really is no difference between the two, other than that the package name is more obviously associated with the class itself than with the objects of the class. You'll have to take our word for it that the objects also know their class. We'll tell you in a bit how to associate an object with a class name, but you can use objects without knowing that. For example, to construct an object using the class method summon and then invoke the instance method speak on the resulting object, you might say this: The summon and speak methods are defined by the Wizard class--or one of the classes from which it inherits. But you shouldn't worry about that. Do not meddle in the affairs of Wizards.$mage = Wizard->summon("Gandalf"); # class method $mage->speak("friend"); # instance method Since the arrow operator is left associative (see Chapter 3, "Unary and Binary Operators"), you can even combine the two statements into one: Sometimes you want to invoke a method without knowing its name ahead of time. You can use the arrow form of method invocation and replace the method name with a simple scalar variable:Wizard->summon("Gandalf")->speak("friend"); Although you're using the name of the method to invoke it indirectly, this usage is not forbidden by use strict 'refs', since all method calls are in fact looked up symbolically at the time they're resolved.$method = "summon"; $mage = Wizard->$method("Gandalf"); # Invoke Wizard->summon $travel = $companion eq "Shadowfax" ? "ride" : "walk"; $mage->$travel("seven leagues"); # Invoke $mage->ride or $mage->walk In our example, we stored the name of a subroutine in $travel, but you could also store a subroutine reference. This bypasses the method lookup algorithm, but sometimes that's exactly what you want to do. See both the section Section 12.5.5, "Private Methods" and the discussion of the can method in the section Section 12.5.3, "UNIVERSAL: The Ultimate Ancestor Class". To create a reference to a particular method being called on a particular instance, see the section Section 12.3.7, "Closures" in Chapter 8, "References". 12.3.2. Method Invocation Using Indirect ObjectsThe second style of method invocation looks like this: METHOD INVOCANT (LIST) METHOD INVOCANT LIST METHOD INVOCANT The parentheses around LIST are optional; if omitted, the method acts as a list operator. So you can have statements like the following, all of which use this style of method call: The list operator syntax should be familiar to you; it's the same style used for passing filehandles to print or printf:$mage = summon Wizard "Gandalf"; $nemesis = summon Balrog home => "Moria", weapon => "whip"; move $nemesis "bridge"; speak $mage "You cannot pass"; break $staff; # safer to use: break $staff (); It's also similar to English sentences like "Give Gollum the Preciousss", so we call it the indirect object form. The invocant is expected in the indirect object slot. When you read about passing a built-in function like system or exec something in its "indirect object slot", this means that you're supplying this extra, comma-less argument in the same place you would when you invoke a method using the indirect object syntax.print STDERR "help!!!\n"; The indirect object form even permits you to specify the INVOCANT as a BLOCK that evaluates to an object (reference) or class (package). This lets you combine those two invocations into one statement this way: speak { summon Wizard "Gandalf" } "friend"; 12.3.3. Syntactic Snafus with Indirect ObjectsOne syntax will often be more readable than the other. The indirect object syntax is less cluttered, but suffers from several forms of syntactic ambiguity. The first is that the LIST part of an indirect object invocation is parsed the same as any other list operator. Thus, the parentheses of: are assumed to surround all the arguments, regardless of what comes afterward. It would therefore be be equivalent to this:enchant $sword ($pips + 2) * $cost; That's unlikely to do what you want: enchant is only being called with $pips + 2, and the method's return value is then multiplied by $cost. As with other list operators, you must also be careful of the precedence of && and || versus and and or.($sword->enchant($pips + 2)) * $cost; For example, this: becomes the intended:name $sword $oldname || "Glamdring"; # can't use "or" here! but this:$sword->name($oldname || "Glamdring"); becomes the dubious:speak $mage "friend" && enter(); # should've been "and" here! which could be fixed by rewriting into one of these equivalent forms:$mage->speak("friend" && enter()); The second syntactic infelicity of the indirect object form is that its INVOCANT is limited to a name, an unsubscripted scalar variable, or a block.[4] As soon as the parser sees one of these, it has its INVOCANT, so it starts looking for its LIST. So these invocations:enter() if $mage->speak("friend"); $mage->speak("friend") && enter(); speak $mage "friend" and enter(); actually parse as these:move $party->{LEADER}; # probably wrong! move $riders[$i]; # probably wrong! rather than what you probably wanted:$party->move->{LEADER}; $riders->move([$i]); The parser only looks a little ways ahead to find the invocant for an indirect object, not even as far as it would look for a unary operator. This oddity does not arise with the first notation, so you might wish to stick with the arrow as your weapon of choice.$party->{LEADER}->move; $riders[$i]->move;
Even English has a similar issue here. Think about the command, "Throw your cat out the window a toy mouse to play with." If you parse that sentence too quickly, you'll end up throwing the cat, not the mouse (unless you notice that the cat is already out the window). Like Perl, English has two different syntaxes for expressing the agent: "Throw your cat the mouse" and "Throw the mouse to your cat." Sometimes the longer form is clearer and more natural, and sometimes the shorter one is. At least in Perl, you're required to use braces around any complicated indirect object. 12.3.4. Package-Quoted ClassesThe final syntactic ambiguity with the indirect object style of method invocation is that it may not be parsed as a method call at all, because the current package may have a subroutine of the same name as the method. When using a class method with a literal package name as the invocant, there is a way to resolve this ambiguity while still keeping the indirect object syntax: package-quote the classname by appending a double colon to it. This is important because the commonly seen notation:$obj = method CLASS::; # forced to be "CLASS"->method will not always behave properly if the current package has a subroutine named new or CLASS. Even if you studiously use the arrow form instead of the indirect object form to invoke methods, this can, on rare occasion, still be a problem. At the cost of extra punctuation noise, the CLASS:: notation guarantees how Perl will parse your method invocation. The first two examples below do not always parse the same way, but the second two do:$obj = new CLASS; # might not parse as method This package-quoting notation can be made prettier with some creative alignment:$obj = new ElvenRing; # could be new("ElvenRing") # or even new(ElvenRing()) $obj = ElvenRing->new; # could be ElvenRing()->new() $obj = new ElvenRing::; # always "ElvenRing"->new() $obj = ElvenRing::->new; # always "ElvenRing"->new() Still, you may say, "Oh, ugh!" at that double colon, so we'll tell you that you can almost always get away with a bare class name, provided two things are true. First, there is no subroutine of the same name as the class. (If you follow the convention that subroutine names like new start lowercase and class names like ElvenRing start uppercase, this is never a problem.) Second, the class has been loaded with one of:$obj = new ElvenRing:: name => "Narya", owner => "Gandalf", domain => "fire", stone => "ruby"; Either of these declarations ensures that Perl knows ElvenRing is a module name, which forces any bare name like new before the class name ElvenRing to be interpreted as a method call, even if you happen to have declared a new subroutine of your own in the current package. People don't generally get into trouble with indirect objects unless they start cramming multiple classes into the same file, in which case Perl might not know that a particular package name was supposed to be a class name. People who name subroutines with names that look like ModuleNames also come to grief eventually.use ElvenRing; require ElvenRing; Copyright © 2002 O'Reilly & Associates. All rights reserved. |
|