From: Michael Witten Date: Tue, 7 Apr 2009 19:59:25 +0000 (-0500) Subject: Docs: Better[?] development of SUPER X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=c7b05296e4d91f7340a7dd0fea0074b185981c1d;p=p5sagit%2Fp5-mst-13.2.git Docs: Better[?] development of SUPER Signed-off-by: Michael Witten --- diff --git a/pod/perlboot.pod b/pod/perlboot.pod index 03b2582..cdd1e02 100644 --- a/pod/perlboot.pod +++ b/pod/perlboot.pod @@ -315,7 +315,7 @@ should always act like an C). So, let's make C an C! -First, we can invoke the C method directly: +The obvious solution is to invoke C directly: # Animal package from before { package Mouse; @@ -328,29 +328,41 @@ First, we can invoke the C method directly: } } -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; @@ -362,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; @@ -389,9 +399,17 @@ 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; + +does I look in the C<@ISA> of C<$class> unless C<$class> happens to +be the current package. =head2 Where we're at so far...