📄 overload.pm
字号:
package overload;$overload::hint_bits = 0x20000;sub nil {}sub OVERLOAD { $package = shift; my %arg = @_; my ($sub, $fb); $ {$package . "::OVERLOAD"}{dummy}++; # Register with magic by touching. *{$package . "::()"} = \&nil; # Make it findable via fetchmethod. for (keys %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 { $package = (caller())[0]; # *{$package . "::OVERLOAD"} = \&OVERLOAD; shift; $package->overload::OVERLOAD(@_);}sub unimport { $package = (caller())[0]; ${$package . "::OVERLOAD"}{dummy}++; # Upgrade the table shift; for (@_) { if ($_ eq 'fallback') { undef $ {$package . "::()"}; } else { delete $ {$package . "::"}{"(" . $_}; } }}sub Overloaded { 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 { my $package = shift; $package = ref $package if ref $package; #$package->can('(""') ov_method mycan($package, '(""'), $package or ov_method mycan($package, '(0+'), $package or ov_method mycan($package, '(bool'), $package or ov_method mycan($package, '(nomethod'), $package;}sub Method { 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 { my $package = ref $_[0]; return "$_[0]" unless $package; bless $_[0], overload::Fake; # Non-overloaded package my $str = "$_[0]"; bless $_[0], $package; # Back $package . substr $str, index $str, '=';}sub StrVal { (OverloadedStringify($_[0]) or ref($_[0]) eq 'Regexp') ? (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;}%constants = ( 'integer' => 0x1000, 'float' => 0x2000, 'binary' => 0x4000, 'q' => 0x8000, 'qr' => 0x10000, );%ops = ( with_assign => "+ - * / % ** << >> x .", assign => "+= -= *= /= %= **= <<= >>= x= .=", num_comparison => "< <= > >= == !=", '3way_comparison'=> "<=> cmp", str_comparison => "lt le gt ge eq ne", binary => "& | ^", unary => "neg ! ~", mutators => '++ --', func => "atan2 cos sin exp abs log sqrt", conversion => 'bool "" 0+', iterators => '<>', dereferencing => '${} @{} %{} &{} *{}', special => 'nomethod fallback =');use warnings::register;sub constant { # Arguments: what, sub while (@_) { if (@_ == 1) { warnings::warnif ("Odd number of arguments for overload::constant"); last; } elsif (!exists $constants {$_ [0]}) { warnings::warnif ("`$_[0]' is not an overloadable type"); } elsif (!ref $_ [1] || "$_[1]" !~ /CODE\(0x[\da-f]+\)$/) { # Can't use C<ref $_[1] eq "CODE"> above as code references can be # blessed, and C<ref> would return the package the ref is blessed into. if (warnings::enabled) { $_ [1] = "undef" unless defined $_ [1]; warnings::warn ("`$_[1]' is not a code reference"); } } else { $^H{$_[0]} = $_[1]; $^H |= $constants{$_[0]} | $overload::hint_bits; } shift, shift; }}sub remove_constant { # Arguments: what, sub while (@_) { delete $^H{$_[0]}; $^H &= ~ $constants{$_[0]}; shift, shift; }}1;__END__=head1 NAMEoverload - Package for overloading perl operations=head1 SYNOPSIS package SomeThing; use overload '+' => \&myadd, '-' => \&mysub; # etc ... package main; $a = new SomeThing 57; $b=5+$a; ... if (overload::Overloaded $b) {...} ... $strval = overload::StrVal $b;=head1 DESCRIPTION=head2 Declaration of overloaded functionsThe compilation directive package Number; use overload "+" => \&add, "*=" => "muas";declares function Number::add() for addition, and method muas() inthe "class" C<Number> (or one of its base classes)for the assignment form C<*=> of multiplication.Arguments of this directive come in (key, value) pairs. Legal valuesare values legal inside a C<&{ ... }> call, so the name of asubroutine, a reference to a subroutine, or an anonymous subroutinewill all work. Note that values specified as strings areinterpreted as methods, not subroutines. Legal keys are listed below.The subroutine C<add> will be called to execute C<$a+$b> if $ais a reference to an object blessed into the package C<Number>, or if $a isnot an object from a package with defined mathemagic addition, but $b is areference to a C<Number>. It can also be called in other situations, likeC<$a+=7>, or C<$a++>. See L<MAGIC AUTOGENERATION>. (Mathemagicalmethods refer to methods triggered by an overloaded mathematicaloperator.)Since overloading respects inheritance via the @ISA hierarchy, theabove declaration would also trigger overloading of C<+> and C<*=> inall the packages which inherit from C<Number>.=head2 Calling Conventions for Binary OperationsThe functions specified in the C<use overload ...> directive are calledwith three (in one particular case with four, see L<Last Resort>)arguments. If the corresponding operation is binary, then the firsttwo arguments are the two arguments of the operation. However, due togeneral object calling conventions, the first argument should always bean object in the package, so in the situation of C<7+$a>, theorder of the arguments is interchanged. It probably does not matterwhen implementing the addition method, but whether the argumentsare reversed is vital to the subtraction method. The method canquery this information by examining the third argument, which can takethree different values:=over 7=item FALSEthe order of arguments is as in the current operation.=item TRUEthe arguments are reversed.=item C<undef>the current operation is an assignment variant (as inC<$a+=7>), but the usual function is called instead. This additionalinformation can be used to generate some optimizations. CompareL<Calling Conventions for Mutators>.=back=head2 Calling Conventions for Unary OperationsUnary operation are considered binary operations with the secondargument being C<undef>. Thus the functions that overloads C<{"++"}>is called with arguments C<($a,undef,'')> when $a++ is executed.=head2 Calling Conventions for MutatorsTwo types of mutators have different calling conventions:=over=item C<++> and C<-->The routines which implement these operators are expected to actuallyI<mutate> their arguments. So, assuming that $obj is a reference to anumber, sub incr { my $n = $ {$_[0]}; ++$n; $_[0] = bless \$n}is an appropriate implementation of overloaded C<++>. Note that sub incr { ++$ {$_[0]} ; shift }is OK if used with preincrement and with postincrement. (In the caseof postincrement a copying will be performed, see L<Copy Constructor>.)=item C<x=> and other assignment versionsThere is nothing special about these methods. They may change thevalue of their arguments, and may leave it as is. The result is goingto be assigned to the value in the left-hand-side if different fromthis value.This allows for the same method to be used as overloaded C<+=> andC<+>. Note that this is I<allowed>, but not recommended, since by thesemantic of L<"Fallback"> Perl will call the method for C<+> anyway,if C<+=> is not overloaded.=backB<Warning.> Due to the presense of assignment versions of operations,routines which may be called in assignment context may createself-referential structures. Currently Perl will not free self-referentialstructures until cycles are C<explicitly> broken. You may get problemswhen traversing your structures too.Say, use overload '+' => sub { bless [ \$_[0], \$_[1] ] };is asking for trouble, since for code C<$obj += $foo> the subroutineis called as C<$obj = add($obj, $foo, undef)>, or C<$obj = [\$obj,\$foo]>. If using such a subroutine is an important optimization, onecan overload C<+=> explicitly by a non-"optimized" version, or switchto non-optimized version if C<not defined $_[2]> (seeL<Calling Conventions for Binary Operations>).Even if no I<explicit> assignment-variants of operators are present inthe script, they may be generated by the optimizer. Say, C<",$obj,"> orC<',' . $obj . ','> may be both optimized to my $tmp = ',' . $obj; $tmp .= ',';=head2 Overloadable OperationsThe following symbols can be specified in C<use overload> directive:=over 5=item * I<Arithmetic operations> "+", "+=", "-", "-=", "*", "*=", "/", "/=", "%", "%=", "**", "**=", "<<", "<<=", ">>", ">>=", "x", "x=", ".", ".=",For these operations a substituted non-assignment variant can be called ifthe assignment variant is not available. Methods for operations "C<+>","C<->", "C<+=>", and "C<-=>" can be called to automatically generateincrement and decrement methods. The operation "C<->" can be used toautogenerate missing methods for unary minus or C<abs>.See L<"MAGIC AUTOGENERATION">, L<"Calling Conventions for Mutators"> andL<"Calling Conventions for Binary Operations">) for details of thesesubstitutions.=item * I<Comparison operations> "<", "<=", ">", ">=", "==", "!=", "<=>", "lt", "le", "gt", "ge", "eq", "ne", "cmp",If the corresponding "spaceship" variant is available, it can beused to substitute for the missing operation. During C<sort>ingarrays, C<cmp> is used to compare values subject to C<use overload>.=item * I<Bit operations> "&", "^", "|", "neg", "!", "~","C<neg>" stands for unary minus. If the method for C<neg> is notspecified, it can be autogenerated using the method forsubtraction. If the method for "C<!>" is not specified, it can beautogenerated using the methods for "C<bool>", or "C<\"\">", or "C<0+>".=item * I<Increment and decrement> "++", "--",If undefined, addition and subtraction methods can beused instead. These operations are called both in prefix andpostfix form.=item * I<Transcendental functions> "atan2", "cos", "sin", "exp", "abs", "log", "sqrt",If C<abs> is unavailable, it can be autogenerated using methodsfor "E<lt>" or "E<lt>=E<gt>" combined with either unary minus or subtraction.=item * I<Boolean, string and numeric conversion> "bool", "\"\"", "0+",If one or two of these operations are not overloaded, the remaining ones canbe used instead. C<bool> is used in the flow control operators(like C<while>) and for the ternary "C<?:>" operation. These functions canreturn any arbitrary Perl value. If the corresponding operation for this valueis overloaded too, that operation will be called again with this value.As a special case if the overload returns the object itself then it willbe used directly. An overloaded conversion returning the object isprobably a bug, because you're likely to get something that looks likeC<YourPackage=HASH(0x8172b34)>.=item * I<Iteration> "<>"If not overloaded, the argument will be converted to a filehandle orglob (which may require a stringification). The same overloadinghappens both for the I<read-filehandle> syntax C<E<lt>$varE<gt>> andI<globbing> syntax C<E<lt>${var}E<gt>>.=item * I<Dereferencing> '${}', '@{}', '%{}', '&{}', '*{}'.If not overloaded, the argument will be dereferenced I<as is>, thusshould be of correct type. These functions should return a referenceof correct type, or another object with overloaded dereferencing.As a special case if the overload returns the object itself then itwill be used directly (provided it is the correct type).The dereference operators must be specified explicitly they will not be passed to"nomethod".=item * I<Special> "nomethod", "fallback", "=",see L<SPECIAL SYMBOLS FOR C<use overload>>.=backSee L<"Fallback"> for an explanation of when a missing method can beautogenerated.A computer-readable form of the above table is available in the hash%overload::ops, with values being space-separated lists of names: with_assign => '+ - * / % ** << >> x .', assign => '+= -= *= /= %= **= <<= >>= x= .=', num_comparison => '< <= > >= == !=', '3way_comparison'=> '<=> cmp', str_comparison => 'lt le gt ge eq ne', binary => '& | ^', unary => 'neg ! ~', mutators => '++ --', func => 'atan2 cos sin exp abs log sqrt', conversion => 'bool "" 0+', iterators => '<>', dereferencing => '${} @{} %{} &{} *{}', special => 'nomethod fallback ='=head2 Inheritance and overloadingInheritance interacts with overloading in two ways.=over=item Strings as values of C<use overload> directiveIf C<value> in use overload key => value;is a string, it is interpreted as a method name.=item Overloading of an operation is inherited by derived classesAny class derived from an overloaded class is also overloaded. Theset of overloaded methods is the union of overloaded methods of allthe ancestors. If some method is overloaded in several ancestor, thenwhich description will be used is decided by the usual inheritancerules:If C<A> inherits from C<B> and C<C> (in this order), C<B> overloadsC<+> with C<\&D::plus_sub>, and C<C> overloads C<+> by C<"plus_meth">,then the subroutine C<D::plus_sub> will be called to implementoperation C<+> for an object in package C<A>.=backNote that since the value of the C<fallback> key is not a subroutine,its inheritance is not governed by the above rules. In the currentimplementation, the value of C<fallback> in the first overloadedancestor is used, but this is accidental and subject to change.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -