X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2Foverload.pm;h=2bbb639d9b5673c736ecc2feec9c2e58dc93b8d6;hb=e7ea3e70155d0bea30720ba41eb6bb6742aac0d1;hp=54d2cbb441131676ce5920acd730465c4d4309be;hpb=cb1a09d0194fed9b905df7b04a4bc031d354609d;p=p5sagit%2Fp5-mst-13.2.git diff --git a/lib/overload.pm b/lib/overload.pm index 54d2cbb..2bbb639 100644 --- a/lib/overload.pm +++ b/lib/overload.pm @@ -1,12 +1,27 @@ package overload; +sub nil {} + sub OVERLOAD { $package = shift; my %arg = @_; - my $hash = \%{$package . "::OVERLOAD"}; + my ($sub, $fb); + $ {$package . "::OVERLOAD"}{dummy}++; # Register with magic by touching. + *{$package . "::()"} = \&nil; # Make it findable via fetchmethod. for (keys %arg) { - $hash->{$_} = $arg{$_}; + if ($_ eq 'fallback') { + $fb = $arg{$_}; + } else { + $sub = $arg{$_}; + if (not ref $sub and $sub !~ /::/) { + $ {$package . "::(" . $_} = $sub; + $sub = \&nil; + } + #print STDERR "Setting `$ {'package'}::\cO$_' to \\&`$sub'.\n"; + *{$package . "::(" . $_} = \&{ $sub }; + } } + ${$package . "::()"} = $fb; # Make it findable too (fallback only). } sub import { @@ -18,44 +33,73 @@ sub import { sub unimport { $package = (caller())[0]; - my $hash = \%{$package . "::OVERLOAD"}; + ${$package . "::OVERLOAD"}{dummy}++; # Upgrade the table shift; for (@_) { - delete $hash->{$_}; + if ($_ eq 'fallback') { + undef $ {$package . "::()"}; + } else { + delete $ {$package . "::"}{"(" . $_}; + } } } sub Overloaded { - defined ($package = ref $_[0]) and defined %{$package . "::OVERLOAD"}; + my $package = shift; + $package = ref $package if ref $package; + $package->can('()'); +} + +sub ov_method { + my $globref = shift; + return undef unless $globref; + my $sub = \&{*$globref}; + return $sub if $sub ne \&nil; + return shift->can($ {*$globref}); } sub OverloadedStringify { - defined ($package = ref $_[0]) and - defined %{$package . "::OVERLOAD"} and - exists $ {$package . "::OVERLOAD"}{'""'} and - defined &{$ {$package . "::OVERLOAD"}{'""'}}; + my $package = shift; + $package = ref $package if ref $package; + #$package->can('(""') + ov_method mycan($package, '(""'), $package; } sub Method { - defined ($package = ref $_[0]) and - defined %{$package . "::OVERLOAD"} and - $ {$package . "::OVERLOAD"}{$_[1]}; + my $package = shift; + $package = ref $package if ref $package; + #my $meth = $package->can('(' . shift); + ov_method mycan($package, '(' . shift), $package; + #return $meth if $meth ne \&nil; + #return $ {*{$meth}}; } sub AddrRef { - $package = ref $_[0]; - bless $_[0], Overload::Fake; # Non-overloaded package + my $package = ref $_[0]; + return "$_[0]" unless $package; + bless $_[0], overload::Fake; # Non-overloaded package my $str = "$_[0]"; bless $_[0], $package; # Back - $str; + $package . substr $str, index $str, '='; } sub StrVal { - (OverloadedStringify) ? - (AddrRef) : + (OverloadedStringify($_[0])) ? + (AddrRef(shift)) : "$_[0]"; } +sub mycan { # Real can would leave stubs. + my ($package, $meth) = @_; + return \*{$package . "::$meth"} if defined &{$package . "::$meth"}; + my $p; + foreach $p (@{$package . "::ISA"}) { + my $out = mycan($p, $meth); + return $out if $out; + } + return undef; +} + 1; __END__ @@ -105,9 +149,10 @@ the "class" C (or one of its base classes) for the assignment form C<*=> of multiplication. Arguments of this directive come in (key, value) pairs. Legal values -are values legal inside a C<&{ ... }> call, so the name of a subroutine, -a reference to a subroutine, or an anonymous subroutine will all work. -Legal keys are listed below. +are values legal inside a C<&{ ... }> call, so the name of a +subroutine, a reference to a subroutine, or an anonymous subroutine +will all work. Note that values specified as strings are +interpreted as methods, not subroutines. Legal keys are listed below. The subroutine C will be called to execute C<$a+$b> if $a is a reference to an object blessed into the package C, or if $a is @@ -117,6 +162,10 @@ C<$a+=7>, or C<$a++>. See L. (Mathemagical methods refer to methods triggered by an overloaded mathematical operator.) +Since overloading respects @ISA hierarchy, in fact the above +declaration would also trigger overloading of C<+> and C<*=> in all +the packages which inherit from C. + =head2 Calling Conventions for Binary Operations The functions specified in the C directive are called @@ -186,7 +235,9 @@ arrays, C is used to compare values subject to C. "&", "^", "|", "neg", "!", "~", "C" stands for unary minus. If the method for C is not -specified, it can be autogenerated using the method for subtraction. +specified, it can be autogenerated using the method for +subtraction. If the method for "C" is not specified, it can be +autogenerated using the methods for "C", or "C<\"\">", or "C<0+>". =item * I @@ -201,7 +252,7 @@ postfix form. "atan2", "cos", "sin", "exp", "abs", "log", "sqrt", If C is unavailable, it can be autogenerated using methods -for "<" or "<=>" combined with either unary minus or subtraction. +for "E" or "E=E" combined with either unary minus or subtraction. =item * I @@ -223,6 +274,40 @@ see L>. See L<"Fallback"> for an explanation of when a missing method can be autogenerated. +=head2 Inheritance and overloading + +There are two ways how inheritance interacts with overloading. + +=over + +=item Strings as values of C directive + +If the value of + + use overload key => value; + +directive is a string, it is interpreted as a method name. + +=item Overloading of an operation is inherited by derived classes + +If any of ancestors is overloaded, so is the derived class. The set of +overloaded methods is the union of overloaded methods of all the +ancestors. If some method is overloaded in several ancestor, then +which description will be used is decided by the usual inheritance +rules: + +If C inherits from C and C (in this order), and C +overloads C<+> by C<\&D::plus_sub>, C overloads C<+> by +C<"plus_meth">, then the subroutine C will be called to +implement operation C<+> for an object in package C. + +=back + +Note that since the value of C key is not a subroutine, its +inheritance is not governed by the above rules. Current implementation +is that the value of C in the first overloaded ancestor is +taken, but this may be subject to change. + =head1 SPECIAL SYMBOLS FOR C Three keys are recognized by Perl that are not covered by the above @@ -275,6 +360,9 @@ C<"nomethod"> value, and if this is missing, raises an exception. =back +B C<"fallback"> inheritance via @ISA is not carved in stone +yet, see L<"Inheritance and overloading">. + =head2 Copy Constructor The value for C<"="> is a reference to a function with three @@ -361,6 +449,11 @@ can be expressed in terms of C<$aE0> and C<-$a> (or C<0-$a>). can be expressed in terms of subtraction. +=item I + +C and C can be expressed in terms of boolean conversion, or +string or numerical conversion. + =item I can be expressed in terms of string conversion. @@ -369,7 +462,7 @@ can be expressed in terms of string conversion. can be expressed in terms of its "spaceship" counterpart: either C=E> or C: - + <, >, <=, >=, ==, != in terms of <=> lt, gt, le, ge, eq, ne in terms of cmp @@ -433,16 +526,21 @@ Returns C or a reference to the method that implements C. What follows is subject to change RSN. -The table of methods for all operations is cached as magic in the -symbol table hash for the package. The table is rechecked for changes due to -C, C, and @ISA only during -Cing; so if they are changed dynamically, you'll need an -additional fake Cing to update the table. - -(Every SVish thing has a magic queue, and magic is an entry in that queue. -This is how a single variable may participate in multiple forms of magic -simultaneously. For instance, environment variables regularly have two -forms at once: their %ENV magic and their taint magic.) +The table of methods for all operations is cached in magic for the +symbol table hash for the package. The cache is invalidated during +processing of C, C, new function +definitions, and changes in @ISA. However, this invalidation remains +unprocessed until the next Cing into the package. Hence if you +want to change overloading structure dynamically, you'll need an +additional (fake) Cing to update the table. + +(Every SVish thing has a magic queue, and magic is an entry in that +queue. This is how a single variable may participate in multiple +forms of magic simultaneously. For instance, environment variables +regularly have two forms at once: their %ENV magic and their taint +magic. However, the magic which implements overloading is applied to +the stashes, which are rarely used directly, thus should not slow down +Perl.) If an object belongs to a package using overload, it carries a special flag. Thus the only speed penalty during arithmetic operations without @@ -451,13 +549,17 @@ overloading is the checking of this flag. In fact, if C is not present, there is almost no overhead for overloadable operations, so most programs should not suffer measurable performance penalties. A considerable effort was made to minimize the overhead -when overload is used and the current operation is overloadable but +when overload is used in some package, but the arguments in question do not belong to packages using overload. When in doubt, test your speed with C and without it. So far there have been no reports of substantial speed degradation if Perl is compiled with optimization turned on. -There is no size penalty for data if overload is not used. +There is no size penalty for data if overload is not used. The only +size penalty if overload is used in some package is that I the +packages acquire a magic during the next Cing into the +package. This magic is three-words-long for packages without +overloading, and carries the cache tabel if the package is overloaded. Copying (C<$a=$b>) is shallow; however, a one-level-deep copying is carried out before any operation that can imply an assignment to the @@ -469,19 +571,31 @@ to be changed are constant (but this is not enforced). =head1 AUTHOR -Ilya Zakharevich >. +Ilya Zakharevich EFE. =head1 DIAGNOSTICS When Perl is run with the B<-Do> switch or its equivalent, overloading induces diagnostic messages. +Using the C command of Perl debugger (see L) one can +deduce which operations are overloaded (and which ancestor triggers +this overloading). Say, if C is overloaded, then the method C<(eq> +is shown by debugger. The method C<()> corresponds to the C +key (in fact a presence of this method shows that this package has +overloading enabled, and it is what is used by the C +function). + =head1 BUGS Because it is used for overloading, the per-package associative array -%OVERLOAD now has a special meaning in Perl. +%OVERLOAD now has a special meaning in Perl. The symbol table is +filled with names looking like line-noise. -As shipped, mathemagical properties are not inherited via the @ISA tree. +For the purpose of inheritance every overloaded package behaves as if +C is present (possibly undefined). This may create +interesting effects if some package is not overloaded, but inherits +from two overloaded packages. This document is confusing.