X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=pod%2Fperlboot.pod;h=cf8e51843ae2c6be8d3656a227209fc76d7d7bf7;hb=18fd877aa5c85a3f8bdc7cb30b117cf8f0fe97a6;hp=afe9837986bf3fcfb92143b4e152f3dc287bb261;hpb=2ee409f9fc5c2201b0d49c1f13f3c2ae8804305b;p=p5sagit%2Fp5-mst-13.2.git diff --git a/pod/perlboot.pod b/pod/perlboot.pod index afe9837..cf8e518 100644 --- a/pod/perlboot.pod +++ b/pod/perlboot.pod @@ -171,8 +171,8 @@ This method provides the constant text for the sound itself. { package Cow; sub sound { "moooo" } sub speak { - my $class = shift; - print "a $class goes ", $class->sound, "!\n"; + my $class = shift; + print "a $class goes ", $class->sound, "!\n"; } } @@ -183,8 +183,8 @@ returns C. But how different would this be for the C? { package Horse; sub sound { "neigh" } sub speak { - my $class = shift; - print "a $class goes ", $class->sound, "!\n"; + my $class = shift; + print "a $class goes ", $class->sound, "!\n"; } } @@ -199,8 +199,8 @@ definition for C: { package Animal; sub speak { - my $class = shift; - print "a $class goes ", $class->sound, "!\n"; + my $class = shift; + print "a $class goes ", $class->sound, "!\n"; } } @@ -283,8 +283,8 @@ Let's add a mouse, which can barely be heard: sub sound { "squeak" } sub speak { my $class = shift; - print "a $class goes ", $class->sound, "!\n"; - print "[but you can barely hear it!]\n"; + print "a $class goes ", $class->sound, "!\n"; + print "[but you can barely hear it!]\n"; } } @@ -296,17 +296,26 @@ which results in: [but you can barely hear it!] Here, C has its own speaking routine, so C<< Mouse->speak >> -doesn't immediately invoke C<< Animal->speak >>. This is known as -"overriding". In fact, we didn't even need to say that a C was -an C at all, since all of the methods needed for C are -completely defined with C. - -But we've now duplicated some of the code from C<< Animal->speak >>, -and this can once again be a maintenance headache. So, can we avoid -that? Can we say somehow that a C does everything any other -C does, but add in the extra comment? Sure! - -First, we can invoke the C method directly: +doesn't immediately invoke C<< Animal->speak >>. This is known as +"overriding". In fact, we don't even need to say that a C is +an C at all, because all of the methods needed for C are +completely defined for C; this is known as "duck typing": +"If it walks like a duck and quacks like a duck, I would call it a duck" +(James Whitcomb). However, it would probably be beneficial to allow a +closer examination to conclude that a C is indeed an C, +so it is actually better to define C with C as its base +(that is, it is better to "derive C from C"). + +Moreover, this duplication of code could become a maintenance headache +(though code-reuse is not actually a good reason for inheritance; good +design practices dictate that a derived class should be usable wherever +its base class is usable, which might not be the outcome if code-reuse +is the sole criterion for inheritance. Just remember that a C +should always act like an C). + +So, let's make C an C! + +The obvious solution is to invoke C directly: # Animal package from before { package Mouse; @@ -315,33 +324,45 @@ First, we can invoke the C method directly: sub speak { my $class = shift; Animal::speak($class); - print "[but you can barely hear it!]\n"; + print "[but you can barely hear it!]\n"; } } -Note that we have to include the C<$class> parameter (almost surely -the value of C<"Mouse">) as the first parameter to C, -since we've stopped using the method arrow. Why did we stop? Well, -if we invoke C<< Animal->speak >> there, the first parameter to the -method will be C<"Animal"> not C<"Mouse">, and when time comes for it -to call for the C, it won't have the right class to come back -to this package. - -Invoking C directly is a mess, however. What if -C didn't exist before, and was being inherited from a -class mentioned in C<@Animal::ISA>? Because we are no longer using -the method arrow, we get one and only one chance to hit the right -subroutine. - -Also note that the C classname is now hardwired into the -subroutine selection. This is a mess if someone maintains the code, -changing C<@ISA> for C and didn't notice C there in -C. So, this is probably not the right way to go. +Note that we're using C. If we were to invoke +C<< Animal->speak >> instead, the first parameter to C +would automatically be C<"Animal"> rather than C<"Mouse">, so that +the call to C<< $class->sound >> in C would become +C<< Animal->sound >> rather than C<< Mouse->sound >>. + +Also, without the method arrow C<< -> >>, it becomes necessary to specify +the first parameter to C ourselves, which is why C<$class> +is explicitly passed: C. + +However, invoking C directly is a mess: Firstly, it assumes +that the C method is a member of the C class; what if C +actually inherits C from its own base? Because we are no longer using +C<< -> >> to access C, the special method look up mechanism wouldn't be +used, so C wouldn't even be found! + +The second problem is more subtle: C is now hardwired into the subroutine +selection. Let's assume that C does exist. What happens when, +at a later time, someone expands the class hierarchy by having C +inherit from C instead of C. Unless the invocation of C +is also changed to an invocation of C, centuries worth of taxonomical +classification could be obliterated! + +What we have here is a fragile or leaky abstraction; it is the beginning of a +maintenance nightmare. What we need is the ability to search for the right +method wih as few assumptions as possible. =head2 Starting the search from a different place -A better solution is to tell Perl to search from a higher place -in the inheritance chain: +A I solution is to tell Perl where in the inheritance chain to begin searching +for C. This can be achieved with a modified version of the method arrow C<< -> >>: + + ClassName->FirstPlaceToLook::method + +So, the improved C class is: # same Animal as before { package Mouse; @@ -353,22 +374,20 @@ in the inheritance chain: } } -Ahh. This works. Using this syntax, we start with C to find -C, and use all of C's inheritance chain if not found -immediately. And yet the first parameter will be C<$class>, so the -found C method will get C as its first entry, and -eventually work its way back to C for the details. +Using this syntax, we start with C to find C, and then +use all of C's inheritance chain if it is not found immediately. +As usual, the first parameter to C would be C<$class>, so we no +longer need to pass C<$class> explicitly to C. -But this isn't the best solution. We still have to keep the C<@ISA> -and the initial search package coordinated. Worse, if C had -multiple entries in C<@ISA>, we wouldn't necessarily know which one -had actually defined C. So, is there an even better way? +But what about the second problem? We're still hardwiring C into +the method lookup. =head2 The SUPER way of doing things -By changing the C class to the C class in that -invocation, we get a search of all of our super classes (classes -listed in C<@ISA>) automatically: +If C is replaced with the special placeholder C in that +invocation, then the contents of C's C<@ISA> are used for the +search, beginning with C<$ISA[0]>. So, all of the problems can be fixed +as follows: # same Animal as before { package Mouse; @@ -380,11 +399,19 @@ listed in C<@ISA>) automatically: } } -So, C means look in the current package's C<@ISA> for -C, invoking the first one found. Note that it does I look in -the C<@ISA> of C<$class>. +In general, C means look in the current package's C<@ISA> +for a class that implements C, and invoke the first one found. +The placeholder is called C, because many other languages refer +to base classes as "Iclasses", and Perl likes to be eclectic. + +Note that a call such as + + $class->SUPER::method; -=head2 Where we're at so far... +does I look in the C<@ISA> of C<$class> unless C<$class> happens to +be the current package. + +=head2 Let's review... So far, we've seen the method arrow syntax: @@ -399,20 +426,21 @@ which constructs an argument list of: ("Class", @args) -and attempts to invoke +and attempts to invoke: - Class::method("Class", @Args); + Class::method("Class", @args); However, if C is not found, then C<@Class::ISA> is examined -(recursively) to locate a package that does indeed contain C, +(recursively) to locate a class (a package) that does indeed contain C, and that subroutine is invoked instead. -Using this simple syntax, we have class methods, (multiple) -inheritance, overriding, and extending. Using just what we've seen so -far, we've been able to factor out common code, and provide a nice way -to reuse implementations with variations. This is at the core of what -objects provide, but objects also provide instance data, which we -haven't even begun to cover. +Using this simple syntax, we have class methods, (multiple) inheritance, +overriding, and extending. Using just what we've seen so far, we've +been able to factor out common code (though that's never a good reason +for inheritance!), and provide a nice way to reuse implementations with +variations. + +Now, what about data? =head2 A horse is a horse, of course of course -- or is it? @@ -437,61 +465,61 @@ sound, and the output of: a Horse goes neigh! But all of our Horse objects would have to be absolutely identical. -If I add a subroutine, all horses automatically share it. That's +If we add a subroutine, all horses automatically share it. That's great for making horses the same, but how do we capture the -distinctions about an individual horse? For example, suppose I want -to give my first horse a name. There's got to be a way to keep its +distinctions of an individual horse? For example, suppose we want +to give our first horse a name. There's got to be a way to keep its name separate from the other horses. -We can do that by drawing a new distinction, called an "instance". -An "instance" is generally created by a class. In Perl, any reference -can be an instance, so let's start with the simplest reference -that can hold a horse's name: a scalar reference. +That is to say, we want particular instances of C to have +different names. + +In Perl, any reference can be an "instance", so let's start with the +simplest reference that can hold a horse's name: a scalar reference. my $name = "Mr. Ed"; - my $talking = \$name; + my $horse = \$name; -So now C<$talking> is a reference to what will be the instance-specific -data (the name). The final step in turning this into a real instance -is with a special operator called C: +So, now C<$horse> is a reference to what will be the instance-specific +data (the name). The final step is to turn this reference into a real +instance of a C by using the special operator C: - bless $talking, Horse; + bless $horse, Horse; This operator stores information about the package named C into the thing pointed at by the reference. At this point, we say -C<$talking> is an instance of C. That is, it's a specific +C<$horse> is an instance of C. That is, it's a specific horse. The reference is otherwise unchanged, and can still be used with traditional dereferencing operators. =head2 Invoking an instance method -The method arrow can be used on instances, as well as names of -packages (classes). So, let's get the sound that C<$talking> makes: +The method arrow can be used on instances, as well as classes (the names +of packages). So, let's get the sound that C<$horse> makes: - my $noise = $talking->sound; + my $noise = $horse->sound("some", "unnecessary", "args"); -To invoke C, Perl first notes that C<$talking> is a blessed +To invoke C, Perl first notes that C<$horse> is a blessed reference (and thus an instance). It then constructs an argument -list, in this case from just C<($talking)>. (Later we'll see that -arguments will take their place following the instance variable, -just like with classes.) +list, as per usual. Now for the fun part: Perl takes the class in which the instance was -blessed, in this case C, and uses that to locate the subroutine -to invoke the method. In this case, C is found directly -(without using inheritance), yielding the final subroutine invocation: +blessed, in this case C, and uses that class to locate the +subroutine. In this case, C is found directly (without +using inheritance). In the end, it is as though our initial line were +written as follows: - Horse::sound($talking) + my $noise = Horse::sound($horse, "some", "unnecessary", "args"); Note that the first parameter here is still the instance, not the name of the class as before. We'll get C as the return value, and that'll end up as the C<$noise> variable above. -If Horse::sound had not been found, we'd be wandering up the -C<@Horse::ISA> list to try to find the method in one of the -superclasses, just as for a class method. The only difference between -a class method and an instance method is whether the first parameter -is an instance (a blessed reference) or a class name (a string). +If Horse::sound had not been found, we'd be wandering up the C<@Horse::ISA> +array, trying to find the method in one of the superclasses. The only +difference between a class method and an instance method is whether the +first parameter is an instance (a blessed reference) or a class name (a +string). =head2 Accessing the instance data @@ -508,16 +536,22 @@ the name: } } -Now we call for the name: +Inside C, the C<@_> array contains: + + ($horse, "some", "unnecessary", "args") + +so the C stores C<$horse> into C<$self>. Then, C<$self> gets +de-referenced with C<$$self> as normal, yielding C<"Mr. Ed">. + +It's traditional to C the first parameter into a variable named +C<$self> for instance methods and into a variable named C<$class> for +class methods. - print $talking->name, " says ", $talking->sound, "\n"; +Then, the following line: -Inside C, the C<@_> array contains just C<$talking>, -which the C stores into C<$self>. (It's traditional to shift -the first parameter off into a variable named C<$self> for instance -methods, so stay with that unless you have strong reasons otherwise.) -Then, C<$self> gets de-referenced as a scalar ref, yielding C, -and we're done with that. The result is: + print $horse->name, " says ", $horse->sound, "\n"; + +outputs: Mr. Ed says neigh. @@ -527,31 +561,32 @@ Of course, if we constructed all of our horses by hand, we'd most likely make mistakes from time to time. We're also violating one of the properties of object-oriented programming, in that the "inside guts" of a Horse are visible. That's good if you're a veterinarian, -but not if you just like to own horses. So, let's let the Horse class -build a new horse: +but not if you just like to own horses. So, let's have the Horse +class handle the details inside a class method: { package Horse; @ISA = qw(Animal); sub sound { "neigh" } sub name { - my $self = shift; + my $self = shift; # instance method, so use $self $$self; } sub named { - my $class = shift; + my $class = shift; # class method, so use $class my $name = shift; bless \$name, $class; } } -Now with the new C method, we can build a horse: +Now with the new C method, we can build a horse as follows: - my $talking = Horse->named("Mr. Ed"); + my $horse = Horse->named("Mr. Ed"); Notice we're back to a class method, so the two arguments to C are C and C. The C operator -not only blesses C<$name>, it also returns the reference to C<$name>, -so that's fine as a return value. And that's how to build a horse. +not only blesses C<\$name>, it also returns that reference. + +This C method is called a "constructor". We've called the constructor C here, so that it quickly denotes the constructor's argument as the name for this particular C. @@ -568,7 +603,7 @@ right?) But was there anything specific to C in that method? No. Therefore, it's also the same recipe for building anything else that inherited from -C, so let's put it there: +C, so let's put C and C there: { package Animal; sub speak { @@ -592,8 +627,8 @@ C, so let's put it there: Ahh, but what happens if we invoke C on an instance? - my $talking = Horse->named("Mr. Ed"); - $talking->speak; + my $horse = Horse->named("Mr. Ed"); + $horse->speak; We get a debugging value: @@ -614,9 +649,7 @@ classname). Let's modify the C method first to notice the change: sub name { my $either = shift; - ref $either - ? $$either # it's an instance, return name - : "an unnamed $either"; # it's a class, return generic + ref $either ? $$either : "Any $either"; } Here, the C operator comes in handy to select either the @@ -624,9 +657,9 @@ dereference or a derived string. Now we can use this with either an instance or a class. Note that I've changed the first parameter holder to C<$either> to show that this is intended: - my $talking = Horse->named("Mr. Ed"); - print Horse->name, "\n"; # prints "an unnamed Horse\n" - print $talking->name, "\n"; # prints "Mr Ed.\n" + my $horse = Horse->named("Mr. Ed"); + print Horse->name, "\n"; # prints "Any Horse\n" + print $horse->name, "\n"; # prints "Mr Ed.\n" and now we'll fix C to use this: @@ -650,9 +683,7 @@ Let's train our animals to eat: } sub name { my $either = shift; - ref $either - ? $$either # it's an instance, return name - : "an unnamed $either"; # it's a class, return generic + ref $either ? $$either : "Any $either"; } sub speak { my $either = shift; @@ -675,19 +706,19 @@ Let's train our animals to eat: And now try it out: - my $talking = Horse->named("Mr. Ed"); - $talking->eat("hay"); + my $horse = Horse->named("Mr. Ed"); + $horse->eat("hay"); Sheep->eat("grass"); which prints: Mr. Ed eats hay. - an unnamed Sheep eats grass. + Any Sheep eats grass. An instance method with parameters gets invoked with the instance, and then the list of parameters. So that first invocation is like: - Animal::eat($talking, "hay"); + Animal::eat($horse, "hay"); =head2 More interesting instances @@ -710,42 +741,77 @@ Let's make a sheep that has a name and a color: so C<< $bad->{Name} >> has C, and C<< $bad->{Color} >> has C. But we want to make C<< $bad->name >> access the name, and that's now messed up because it's expecting a scalar reference. Not -to worry, because that's pretty easy to fix up: +to worry, because that's pretty easy to fix up. + +One solution is to override C and C by +defining them anew in C, but then any methods added later to +C might still mess up, and we'd have to override all of those +too. Therefore, it's never a good idea to define the data layout in a +way that's different from the data layout of the base classes. In fact, +it's a good idea to use blessed hash references in all cases. Also, this +is why it's important to have constructors do the low-level work. So, +let's redefine C: ## in Animal sub name { my $either = shift; - ref $either ? - $either->{Name} : - "an unnamed $either"; + ref $either ? $either->{Name} : "Any $either"; } - -And of course C still builds a scalar sheep, so let's fix that -as well: - - ## in Animal sub named { my $class = shift; my $name = shift; - my $self = { Name => $name, Color => $class->default_color }; + my $self = { Name => $name }; bless $self, $class; } +Of course, we still need to override C in order to handle +constructing a C with a certain color: + + ## in Sheep + sub named { + my ($class, $name) = @_; + my $self = $class->SUPER::named(@_); + $$self{Color} = $class->default_color; + $self + } + +(Note that C<@_> contains the parameters to C.) + What's this C? Well, if C has only the name, -we still need to set a color, so we'll have a class-specific initial color. +we still need to set a color, so we'll have a class-specific default color. For a sheep, we might define it as white: ## in Sheep sub default_color { "white" } -And then to keep from having to define one for each additional class, -we'll define a "backstop" method that serves as the "default default", -directly in C: +Now: + + my $sheep = Sheep->named("Bad"); + print $sheep->{Color}, "\n"; + +outputs: + + white + +Now, there's nothing particularly specific to C when it comes +to color, so let's remove C and implement C +to handle color instead: + + ## in Animal + sub named { + my ($class, $name) = @_; + my $self = { Name => $name, Color => $class->default_color }; + bless $self, $class; + } + +And then to keep from having to define C for each additional +class, we'll define a method that serves as the "default default" directly +in C: ## in Animal sub default_color { "brown" } -Now, because C and C were the only methods that +Of course, because C and C were the only methods that referenced the "structure" of the object, the rest of the methods can remain the same, so C still works as before. @@ -767,9 +833,9 @@ in-place, rather than with a C. (This saves us a bit of time for something that may be invoked frequently.) And now we can fix that color for Mr. Ed: - my $talking = Horse->named("Mr. Ed"); - $talking->set_color("black-and-white"); - print $talking->name, " is colored ", $talking->color, "\n"; + my $horse = Horse->named("Mr. Ed"); + $horse->set_color("black-and-white"); + print $horse->name, " is colored ", $horse->color, "\n"; which results in: @@ -777,14 +843,13 @@ which results in: =head2 Summary -So, now we have class methods, constructors, instance methods, -instance data, and even accessors. But that's still just the -beginning of what Perl has to offer. We haven't even begun to talk -about accessors that double as getters and setters, destructors, -indirect object notation, subclasses that add instance data, per-class -data, overloading, "isa" and "can" tests, C class, and so -on. That's for the rest of the Perl documentation to cover. -Hopefully, this gets you started, though. +So, now we have class methods, constructors, instance methods, instance +data, and even accessors. But that's still just the beginning of what +Perl has to offer. We haven't even begun to talk about accessors that +double as getters and setters, destructors, indirect object notation, +overloading, "isa" and "can" tests, the C class, and so on. +That's for the rest of the Perl documentation to cover. Hopefully, this +gets you started, though. =head1 SEE ALSO @@ -801,10 +866,14 @@ Class::MethodMaker and Tie::SecureHash =head1 COPYRIGHT Copyright (c) 1999, 2000 by Randal L. Schwartz and Stonehenge -Consulting Services, Inc. Permission is hereby granted to distribute -this document intact with the Perl distribution, and in accordance -with the licenses of the Perl distribution; derived documents must -include this copyright notice intact. +Consulting Services, Inc. + +Copyright (c) 2009 by Michael F. Witten. + +Permission is hereby granted to distribute this document intact with +the Perl distribution, and in accordance with the licenses of the Perl +distribution; derived documents must include this copyright notice +intact. Portions of this text have been derived from Perl Training materials originally appearing in the I