From: Ilmari Karonen Date: Sun, 8 Apr 2001 23:14:29 +0000 (+0300) Subject: Partial rewrite of perlobj.pod X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=5d9f8747f2e66f41f2988471654fe83786226629;p=p5sagit%2Fp5-mst-13.2.git Partial rewrite of perlobj.pod Message-ID: Rearrange and rewrite the Method Invocation section to explain the concepts in nicer order. p4raw-id: //depot/perl@9658 --- diff --git a/pod/perlobj.pod b/pod/perlobj.pod index 53009c5..e0586b5 100644 --- a/pod/perlobj.pod +++ b/pod/perlobj.pod @@ -227,117 +227,104 @@ and then uses that as an ordinary reference. =head2 Method Invocation -There are two ways to invoke a method, one of which you're already -familiar with, and the other of which will look familiar. Perl 4 -already had an "indirect object" syntax that you use when you say +For various historical and other reasons, Perl offers two equivalent +ways to write a method call. The simpler and more common way is to use +the arrow notation: - print STDERR "help!!!\n"; + my $fred = Critter->find("Fred"); + $fred->display("Height", "Weight"); -This same syntax can be used to call either class or instance methods. -We'll use the two methods defined above, the class method to lookup -an object reference and the instance method to print out its attributes. +You should already be familiar with the C<< -> >> operator from using +references. In fact, since C<$fred> above is a reference to an object, +you could think of the method call as just another form of +dereferencing. - $fred = find Critter "Fred"; - display $fred 'Height', 'Weight'; +Whatever is on the left side of the arrow, whether a reference or a +class name, is passed to the method subroutine as its first argument. +So the above code is mostly equivalent to: -These could be combined into one statement by using a BLOCK in the -indirect object slot: + my $fred = Critter::find("Critter", "Fred"); + Critter::display($fred, "Height", "Weight"); - display {find Critter "Fred"} 'Height', 'Weight'; +How does Perl know which package the subroutine is in? By looking at +the left side of the arrow, which must be either a package name or a +reference to an object, i.e. something that has been blessed to a +package. Either way, that's the package Perl starts looking in. If +that package has no subroutine with that name, Perl starts looking for +it in any base classes of that package, and so on. -For C++ fans, there's also a syntax using -> notation that does exactly -the same thing. The parentheses are required if there are any arguments. +If you want, you I force Perl to start looking in some other +package: - $fred = Critter->find("Fred"); - $fred->display('Height', 'Weight'); + my $barney = MyCritter->Critter::find("Barney"); + $barney->Critter::display("Height", "Weight"); -or in one statement, +Here C is presumably a subclass of C that defines +its own versions of find() and display(). We haven't specified what +those methods do, but that doesn't matter above since we've forced Perl +to start looking for the subroutines in C. - Critter->find("Fred")->display('Height', 'Weight'); +As a special case of the above, you may use the C pseudo-class to +tell Perl to start looking for the method in the current class's C<@ISA> +list. -There are times when one syntax is more readable, and times when the -other syntax is more readable. The indirect object syntax is less -cluttered, but it has the same ambiguity as ordinary list operators. -Indirect object method calls are usually parsed using the same rule as list -operators: "If it looks like a function, it is a function". (Presuming -for the moment that you think two words in a row can look like a -function name. C++ programmers seem to think so with some regularity, -especially when the first word is "new".) Thus, the parentheses of + package MyCritter; + use base 'Critter'; # sets @MyCritter::ISA = ('Critter'); - new Critter ('Barney', 1.5, 70) - -are assumed to surround ALL the arguments of the method call, regardless -of what comes after. Saying - - new Critter ('Bam' x 2), 1.4, 45 - -would be equivalent to - - Critter->new('Bam' x 2), 1.4, 45 - -which is unlikely to do what you want. Confusingly, however, this -rule applies only when the indirect object is a bareword package name, -not when it's a scalar, a BLOCK, or a C qualified package name. -In those cases, the arguments are parsed in the same way as an -indirect object list operator like print, so - - new Critter:: ('Bam' x 2), 1.4, 45 - -is the same as - - Critter::->new(('Bam' x 2), 1.4, 45) - -For more reasons why the indirect object syntax is ambiguous, see -L<"WARNING"> below. - -There are times when you wish to specify which class's method to use. -Here you can call your method as an ordinary subroutine -call, being sure to pass the requisite first argument explicitly: - - $fred = MyCritter::find("Critter", "Fred"); - MyCritter::display($fred, 'Height', 'Weight'); + sub display { + my ($self, @args) = @_; + $self->SUPER::display("Name", @args); + } -Unlike method calls, function calls don't consider inheritance. If you wish -merely to specify that Perl should I looking for a method in a -particular package, use an ordinary method call, but qualify the method -name with the package like this: +Instead of a class name or an object reference, you can also use any +expression that returns either of those on the left side of the arrow. +So the following statement is valid: - $fred = Critter->MyCritter::find("Fred"); - $fred->MyCritter::display('Height', 'Weight'); + Critter->find("Fred")->display("Height", "Weight"); -If you're trying to control where the method search begins I you're -executing in the class itself, then you may use the SUPER pseudo class, -which says to start looking in your base class's @ISA list without having -to name it explicitly: +and so is even the following: - $self->SUPER::display('Height', 'Weight'); + my $fred = (reverse "rettirC")->find(reverse "derF"); -Please note that the C construct is meaningful I within the -class. +=head2 Indirect Object Syntax -Sometimes you want to call a method when you don't know the method name -ahead of time. You can use the arrow form, replacing the method name -with a simple scalar variable containing the method name or a -reference to the function. +The other way to invoke a method is by using the so-called indirect +object notation. Already in Perl 4, long before objects were +introduced, this syntax was used with filehandles like this: - $method = $fast ? "findfirst" : "findbest"; - $fred->$method(@args); # call by name + print STDERR "help!!!\n"; - if ($coderef = $fred->can($parent . "::findbest")) { - $self->$coderef(@args); # call by coderef - } +The same syntax can be used to call either object or class methods. -=head2 WARNING + my $fred = find Critter "Fred"; + display $fred "Height", "Weight"; -While indirect object syntax may well be appealing to English speakers and -to C++ programmers, be not seduced! It suffers from two grave problems. +Notice that there is no comma between the object or class name and the +parameters. This is how Perl can tell you want an indirect method call +instead of an ordinary subroutine call. -The first problem is that an indirect object is limited to a name, -a scalar variable, or a block, because it would have to do too much -lookahead otherwise, just like any other postfix dereference in the -language. (These are the same quirky rules as are used for the filehandle -slot in functions like C and C.) This can lead to horribly -confusing precedence problems, as in these next two lines: +But what if there are no arguments? In that case, Perl must guess what +you want. Even worse, it must make the guess I. +Usually Perl gets it right, but when it doesn't it, you get a function +call compiled as a method, or vice versa. This can introduce subtle bugs +that are hard to unravel. + +For example, calling a method C in indirect notation -- as C++ +programmers are so wont to do -- can be miscompiled into a subroutine +call if there's already a C function in scope. You'd end up +calling the current package's C as a subroutine, rather than the +desired class's method. The compiler tries to cheat by remembering +bareword Cs, but the grief if it messes up just isn't worth the +years of debugging it would likely take you to track such subtle bugs +down. + +There is another problem with this syntax: the indirect object is +limited to a name, a scalar variable, or a block, because it would have +to do too much lookahead otherwise, just like any other postfix +dereference in the language. (These are the same quirky rules as are +used for the filehandle slot in functions like C and C.) +This can lead to horribly confusing precedence problems, as in these +next two lines: move $obj->{FIELD}; # probably wrong! move $ary[$i]; # probably wrong! @@ -352,24 +339,18 @@ Rather than what you might have expected: $obj->{FIELD}->move(); # You should be so lucky. $ary[$i]->move; # Yeah, sure. -The left side of ``->'' is not so limited, because it's an infix operator, -not a postfix operator. +To get the correct behavior with indirect object syntax, you would have +to use a block around the indirect object: -As if that weren't bad enough, think about this: Perl must guess I whether C and C above are functions or methods. -Usually Perl gets it right, but when it doesn't it, you get a function -call compiled as a method, or vice versa. This can introduce subtle -bugs that are hard to unravel. For example, calling a method C -in indirect notation--as C++ programmers are so wont to do--can -be miscompiled into a subroutine call if there's already a C -function in scope. You'd end up calling the current package's C -as a subroutine, rather than the desired class's method. The compiler -tries to cheat by remembering bareword Cs, but the grief if it -messes up just isn't worth the years of debugging it would likely take -you to track such subtle bugs down. - -The infix arrow notation using ``C<< -> >>'' doesn't suffer from either -of these disturbing ambiguities, so we recommend you use it exclusively. + move {$obj->{FIELD}}; + move {$ary[$i]}; + +Even then, you still have the same potential problem if there happens to +be a function named C in the current package. B >> +notation suffers from neither of these disturbing ambiguities, so we +recommend you use it exclusively.> However, you may still end up having +to read code using the indirect object notation, so it's important to be +familiar with it. =head2 Default UNIVERSAL methods