1package Class::Delegation; 2 3our $VERSION = '1.9.0'; 4 5use strict; 6use Carp; 7 8sub ::DEBUG { 0 }; 9 10my %mappings; 11 12sub import { 13 my $class = shift; 14 my $caller = caller(); 15 while (@_) { 16 push @{$mappings{$caller}}, Class::Delegation::->_new(\@_); 17 } 18} 19 20INIT { 21 foreach my $class (keys %mappings) { 22 _install_delegation_for($class); 23 } 24} 25 26sub _install_delegation_for { 27 use vars '$AUTOLOAD'; 28 no strict 'refs'; 29 my ($class) = @_; 30 my $symbol = "${class}::AUTOLOAD"; 31 print STDERR "Installing $symbol\n" if ::DEBUG; 32 my $real_AUTOLOAD = *{$symbol}{CODE} 33 || sub {croak "Could not delegate $AUTOLOAD"}; 34 35 local $SIG{__WARN__} = sub {}; 36 *$symbol = sub { 37 $$symbol = $AUTOLOAD; 38 my ($class, $method) = $AUTOLOAD =~ m/(.*::)(.*)/; 39 my ($invocant, @args) = @_; 40 print STDERR "Delegating: $AUTOLOAD...\n" if ::DEBUG; 41 use Data::Dumper 'Dumper'; 42 print STDERR "...on: ", Dumper $invocant if ::DEBUG; 43 my @context = ($invocant, $method, @args); 44 $invocant = "${class}${invocant}" unless ref $invocant; 45 my $wantarray = wantarray; 46 my @delegators = _delegators_for(@context); 47 goto &{$real_AUTOLOAD} unless @delegators; 48 my (@results, $delegated); 49 DELEGATOR: foreach my $delegator ( @delegators ) { 50 next if $delegator->{other} && keys %$delegated; 51 my @to = @{$delegator->{to}}; 52 my @as = @{$delegator->{as}}; 53 if (@to==1) { 54 print STDERR "[$to[0]]\n" if ::DEBUG; 55 next DELEGATOR if exists $delegated->{$to[0]}; 56 foreach my $as (@as) { 57 push @results, delegate($delegated,$wantarray,$invocant,$to[0],$as,\@args); 58 } 59 } 60 elsif (@as==1) { 61 print STDERR "[$to[0]]\n" if ::DEBUG; 62 foreach my $to (@to) { 63 next if exists $delegated->{$to}; 64 push @results, delegate($delegated,$wantarray,$invocant,$to,$as[0],\@args); 65 } 66 } 67 else { 68 while (1) { 69 last unless @to && @as; 70 my $to = shift @to; 71 my $as = shift @as; 72 next if exists $delegated->{$to}; 73 push @results, delegate($delegated,$wantarray,$invocant,$to,$as,\@args); 74 } 75 } 76 } 77 goto &{$real_AUTOLOAD} unless keys %$delegated; 78 return $wantarray 79 ? ( @results>1 ? @results : @{$results[0]} ) 80 : ( @results>1 ? \@results : $results[0] ); 81 }; 82 83 unless (*{"${class}::DESTROY"}{CODE} || 84 _delegators_for($class,'DESTROY')) { 85 *{"${class}::DESTROY"} = sub {}; 86 } 87} 88 89sub delegate { 90 my ($delegated,$wantarray,$invocant,$to,$as,$args) = @_; 91 no strict 'refs'; 92 my $target = ref $to ? $to 93 : $to =~ /^->(\w+)$/ ? $invocant->$+() 94 : $to eq -SELF ? $invocant 95 : $invocant->{$to}; 96 return unless eval { 97 $target->can($as) || $target->can('AUTOLOAD') 98 }; 99 my $result = $wantarray 100 ? [$target->$as(@$args)] 101 : $target->$as(@$args); 102 return if $@; 103 $_[0]->{$to}++; 104 return $result 105} 106 107sub _delegators_for { 108 my ($self, $method, @args) = @_; 109 110 my @attrs; 111 my $class = ref($self)||$self; 112 foreach my $candidate ( @{$mappings{$class}} ) { 113 push @attrs, $candidate->{send}->can_send(scalar(@attrs), 114 $candidate->{to}, 115 $candidate->{as}, 116 @_); 117 } 118 return @attrs if @attrs; 119 no strict 'refs'; 120 my @ancestors = @{$class.'::ISA'}; 121 my $parent; 122 while ($parent = shift @ancestors) { 123 next unless exists $mappings{$parent}; 124 foreach my $candidate ( @{$mappings{$parent}} ) { 125 push @attrs, $candidate->{send}->can_send(scalar(@attrs), 126 $candidate->{to}, 127 $candidate->{as}, 128 @_); 129 } 130 return @attrs if @attrs; 131 unshift @ancestors, @{$parent.'::ISA'}; 132 } 133 return @attrs; 134} 135 136sub _new { 137 my ($class, $args) = @_; 138 my ($send, $send_val) = splice @$args, 0, 2; 139 croak "Expected 'send => <method spec>' but found '$send => $send_val'" 140 unless $send eq 'send'; 141 croak "The expected 'to => <attribute spec>' is missing at end of list" 142 unless @$args >= 2; 143 my ($to, $to_val) = splice @$args, 0, 2; 144 croak "Expected 'to => <attribute spec>' but found '$to => $to_val'" 145 unless $to eq 'to'; 146 147 $send_val = _class_for(Send => $send_val)->_new($send_val); 148 my $to_obj = _class_for(To => $to_val)->_new($to_val); 149 my $self = bless { send=>$send_val, to=>$to_obj }, $class; 150 if (($args->[0]||"") eq 'as') { 151 my ($as, $as_val) = splice @$args, 0, 2; 152 croak "Arrays specified for 'to' and 'as' must be same length" 153 unless ref($to_val) ne 'ARRAY' 154 || ref($as_val) ne 'ARRAY' 155 || @$to_val == @$as_val; 156 $self->{as} = _class_for(As => $as_val)->_new($as_val); 157 } 158 else { 159 croak "'to => -SELF' is meaningless without 'as => <new_name>'" 160 if $to_val eq -SELF; 161 $self->{as} = Class::Delegation::As::Sent->_new(); 162 } 163 return $self; 164} 165 166my %allowed; 167@{$allowed{Send}}{qw(ARRAY Regexp CODE)} = (); 168@{$allowed{To}}{qw(ARRAY Regexp CODE)} = (); 169@{$allowed{As}}{qw(ARRAY CODE)} = (); 170 171sub _class_for { 172 my ($subclass, $value) = @_; 173 my $type = ref($value); 174 return "Class::Delegation::${subclass}::SCALAR" unless $type; 175 croak "'\l$subclass' value cannot be $type reference" 176 unless exists $allowed{$subclass}{$type}; 177 return "Class::Delegation::${subclass}::${type}"; 178} 179 180package # Hide from CPAN indexer 181SELF; 182 183sub DESTROY {} 184sub AUTOLOAD { 185 my ($name) = $SELF::AUTOLOAD =~ m/.*::(.+)/; 186 bless \$name, 'SELF' 187} 188use overload 'neg' => sub { "->${$_[0]}" }; 189 190 191package Class::Delegation::Send::SCALAR; 192 193sub _new { 194 return bless {}, "Class::Delegation::Send::ALL" if $_[1] eq '-ALL'; 195 return bless {}, "Class::Delegation::Send::OTHER" if $_[-1] eq '-OTHER'; 196 my $val = pop; 197 return bless \$val, $_[0] 198} 199 200sub can_send { 201 my ($self, $sent, $to, $as, @context) = @_; 202 return { to => [$to->attr_for(@context)], 203 as => [$as->name_for(@context)], 204 } 205 if $$self eq $context[1]; 206 return; 207} 208 209 210package Class::Delegation::Send::ARRAY; 211 212sub _new { 213 my @delegators = 214 map { Class::Delegation::_class_for(Send => $_)->_new($_) } @{$_[1]}; 215 bless \@delegators, $_[0]; 216} 217 218sub can_send { 219 my ($self, @context) = @_; 220 return map { $_->can_send(@context) } @$self; 221} 222 223 224package Class::Delegation::Send::Regexp; 225 226sub _new { 227 my ($class, $regex) = @_; 228 my $self = bless \$regex, $class; 229 return $self; 230} 231 232 233sub can_send { 234 my ($self, $sent, $to, $as, @context) = @_; 235 return { to => [$to->attr_for(@context)], 236 as => [$as->name_for(@context)], 237 } 238 if $context[1] =~ $$self; 239 return; 240} 241 242 243package Class::Delegation::Send::CODE; 244 245sub _new { bless $_[1], $_[0] } 246 247sub can_send { 248 my ($self, $sent, $to, $as, @context) = @_; 249 return { to => [$to->attr_for(@context)], 250 as => [$as->name_for(@context)], 251 } 252 if $self->(@context); 253 return; 254} 255 256package Class::Delegation::Send::ALL; 257 258sub can_send { 259 my ($self, $sent, $to, $as, @context) = @_; 260 return { to => [$to->attr_for(@context)], 261 as => [$as->name_for(@context)], 262 } 263 if $context[1] ne 'DESTROY'; 264 return; 265} 266 267package Class::Delegation::Send::OTHER; 268 269sub can_send { 270 my ($self, $sent, $to, $as, @context) = @_; 271 return { to => [$to->attr_for(@context)], 272 as => [$as->name_for(@context)], 273 other => 1, 274 } 275 if $context[1] ne 'DESTROY'; 276 return; 277} 278 279 280package Class::Delegation::To::SCALAR; 281 282sub _new { 283 my ($class, $value) = @_; 284 return bless {}, "Class::Delegation::To::ALL" if $value eq '-ALL'; 285 return bless \$value, $class 286} 287 288sub attr_for { return ${$_[0]} } 289 290 291package Class::Delegation::To::ARRAY; 292 293sub _new { 294 my ($class, $array) = @_; 295 bless [ map {("Class::Delegation::To::".(ref||"SCALAR"))->_new($_)} @$array ], $class; 296} 297 298sub attr_for { 299 my ($self, @context) = @_; 300 return map { $_->attr_for(@context) } @$self; 301} 302 303package Class::Delegation::To::Regexp; 304 305sub _new { 306 my ($class, $regex) = @_; 307 my $self = bless \$regex, $class; 308 return $self; 309} 310 311sub attr_for { 312 my ($self, $invocant, @context) = @_; 313 print STDERR "[[$$self]]\n" if ::DEBUG; 314 return grep { $_ =~ $$self } keys %$invocant; 315} 316 317 318package Class::Delegation::To::CODE; 319 320sub _new { bless $_[1], $_[0] } 321 322sub attr_for { 323 my ($self, @context) = @_; 324 return $self->(@context) 325} 326 327 328package Class::Delegation::To::ALL; 329 330sub attr_for { 331 my ($self, $invocant, @context) = @_; 332 return keys %$invocant; 333} 334 335 336 337package Class::Delegation::As::SCALAR; 338 339sub _new { 340 my ($class, $value) = @_; 341 bless \$value, $class; 342} 343 344sub name_for { ${$_[0]} } 345 346package Class::Delegation::As::ARRAY; 347 348sub _new { 349 my ($class, $value) = @_; 350 bless $value, $class; 351} 352 353sub name_for { @{$_[0]} } 354 355 356package Class::Delegation::As::Sent; 357 358sub _new { bless {}, $_[0] } 359 360sub name_for { 361 my ($self, $invocant, $method) = @_; 362 return $method; 363} 364 365package Class::Delegation::As::CODE; 366 367sub _new { bless $_[1], $_[0] } 368 369sub name_for { 370 my ($self, @context) = @_; 371 return $self->(@context) 372} 373 3741; 375 376__END__ 377 378=head1 NAME 379 380Class::Delegation - Object-oriented delegation 381 382=head1 VERSION 383 384This document describes version 1.9.0 of Class::Delegation 385released April 23, 2002. 386 387=head1 SYNOPSIS 388 389 package Car; 390 391 use Class::Delegation 392 send => 'steer', 393 to => ["left_front_wheel", "right_front_wheel"], 394 395 send => 'drive', 396 to => ["right_rear_wheel", "left_rear_wheel"], 397 as => ["rotate_clockwise", "rotate_anticlockwise"] 398 399 send => 'power', 400 to => 'flywheel', 401 as => 'brake', 402 403 send => 'brake', 404 to => qr/.*_wheel$/, 405 406 send => 'halt' 407 to => -SELF, 408 as => 'brake', 409 410 send => qr/^MP_(.+)/, 411 to => 'mp3', 412 as => sub { $1 }, 413 414 send => -OTHER, 415 to => 'mp3', 416 417 send => 'debug', 418 to => -ALL, 419 as => 'dump', 420 421 send => -ALL, 422 to => 'logger', 423 ; 424 425 426=head1 BACKGROUND 427 428[Skip to L<"DESCRIPTION"> if you don't care why this module exists] 429 430Inheritance is one of the foundations of object-oriented programming. But 431inheritance has a fundamental limitation: a class can only directly inherit 432once from a given parent class. This limitation occasionally 433leads to awkward work-arounds like this: 434 435 package Left_Front_Wheel; use base qw( Wheel ); 436 package Left_Rear_Wheel; use base qw( Wheel ); 437 package Right_Front_Wheel; use base qw( Wheel ); 438 package Right_Rear_Wheel; use base qw( Wheel ); 439 440 package Car; use base qw(Left_Front_Wheel 441 Left_Rear_Wheel 442 Right_Front_Wheel 443 Right_Rear_Wheel); 444 445Worse still, the method dispatch semantics of most languages (including Perl) 446require that only a single inherited method (in Perl, the one that is 447left-most-depth-first in the inheritance tree) can handle a particular 448method invocation. So if the Wheel class provides methods to steer a 449wheel, drive a wheel, or stop a wheel, then calls such as: 450 451 $car->steer('left'); 452 $car->drive(+55); 453 $car->brake('hard'); 454 455will only be processed by the left front wheel. This will probably not 456produce desirable road behaviour. 457 458It is often argued that it is simply a synecdochic mistake to treat a 459car as a specialized form of four wheels, but this argument is 460I<far> from conclusive. And, regardless of its philosophical merits, programmers often do conceptualize 461composite systems in exactly this way. 462 463The alternative is, of course, to make the four wheels I<attributes> of the 464class, rather than I<ancestors>: 465 466 package Car; 467 468 sub new { 469 bless { left_front_wheel => Wheel->new('steer', 'brake'), 470 left_rear_wheel => Wheel->new('drive', 'brake'), 471 right_front_wheel => Wheel->new('steer', 'brake'), 472 right_rear_wheel => Wheel->new('drive', 'brake'), 473 }, $_[0]; 474 } 475 476Indeed some object-oriented languages (e.g. Self) do away with 477inheritance entirely and rely exclusively on the use of attributes to 478implement class hierarchies. 479 480 481=head2 The problem(s) with attribute-based hierarchies 482 483Using attributes instead of inheritance does solve the problem: 484it allows a Car to directly have four wheels. However, this solution 485creates a new problem: it requires that the class manually redispatch (or 486I<delegate>) every method call: 487 488 sub steer { 489 my $self = shift; 490 return ( $self->{left_front_wheel}->steer(@_), 491 $self->{right_front_wheel}->steer(@_), ); 492 } 493 494 sub drive { 495 my $self = shift; 496 return ( $self->{left_rear_wheel}->drive(@_), 497 $self->{right_rear_wheel}->drive(@_), ); 498 } 499 500 sub brake { 501 my $self = shift; 502 return ( $self->{left_front_wheel}->brake(@_), 503 $self->{left_rear_wheel}->brake(@_), 504 $self->{right_front_wheel}->brake(@_), 505 $self->{right_rear_wheel}->brake(@_), ); 506 } 507 508 509C<AUTOLOAD> methods can help in this regard, but usually at the cost of 510readability and maintainability: 511 512 sub AUTOLOAD { 513 my $self = shift; 514 $AUTOLOAD =~ s/.*:://; 515 my @results; 516 return map { $self->{$_}->$AUTOLOAD(@_) }, 517 grep { $self->{$_}->can($AUTOLOAD) }, 518 keys %$self; 519 } 520 521Often, the simple auto-delegation mechanism shown above cannot 522be used at all, and the various cases must be hand-coded into the C<AUTOLOAD> 523or into separate named methods (as shown earlier). 524 525For example, an electric car might also have a flywheel and an MP3 player: 526 527 sub new { 528 bless { left_front_wheel => Wheel->new('steer', 'brake'), 529 left_rear_wheel => Wheel->new('drive', 'brake'), 530 right_front_wheel => Wheel->new('steer', 'brake'), 531 right_rear_wheel => Wheel->new('drive', 'brake'), 532 flywheel => Flywheel->new(), 533 mp3 => MP3::Player->new(), 534 }, $_[0]; 535 } 536 537The Flywheel class would probably have its own C<brake> method (to 538harvest motive energy from the flywheel) and MP3::Player might have its 539own C<drive> method (to switch between storage devices). 540 541An C<AUTOLOAD> redispatch such as that shown above would then fail very 542badly. Whilst it would prove merely annoying to have one's music skip 543tracks (C<$self-E<gt>{mp3}-E<gt>drive(+10)>) every time one accelerated 544(C<$self-E<gt>{right_rear_wheel}-E<gt>drive(+10)>), it might be disastrous to 545attempt to suck energy out of the flywheel 546(C<$self-E<gt>{flywheel}-E<gt>brake()>) whilst the brakes are trying to feed it 547back in (C<$self-E<gt>{right_rear_wheel}-E<gt>brake()>). 548 549Class-action lawyers I<love> this kind of programming. 550 551 552=head1 DESCRIPTION 553 554The Class::Delegation module simplifies the creation of 555delegation-based class hierarchies, allowing 556a method to be redispatched: 557 558=over 4 559 560=item * 561 562to a single nominated attribute, 563 564=item * 565 566to a collection of nominated attributes in parallel, or 567 568=item * 569 570to any attribute that can handle the message. 571 572=item * 573 574the object itself 575 576=back 577 578These three delegation mechanisms can be specified for: 579 580=over 4 581 582=item * 583 584a single method 585 586=item * 587 588a set of nominated methods collectively 589 590=item * 591 592any as-yet-undelegated methods 593 594=item * 595 596all methods, delegated or not. 597 598=back 599 600=head2 The syntax and semantics of delegation 601 602To cause a hash-based class to delegate method invocations to its 603attributes, the Class::Delegation module is imported into the class, and 604passed a list of method/handler mappings that specify the delegation 605required. Each mapping consists of between one and three key/value 606pairs. For example: 607 608 package Car; 609 610 use Class::Delegation 611 send => 'steer', 612 to => ["left_front_wheel", "right_front_wheel"], 613 614 send => 'drive', 615 to => ["right_rear_wheel", "left_rear_wheel"], 616 as => ["rotate_clockwise", "rotate_anticlockwise"] 617 618 send => 'power', 619 to => 'flywheel', 620 as => 'brake', 621 622 send => 'brake', 623 to => qr/.*_wheel$/, 624 625 send => qr/^MP_(.+)/, 626 to => 'mp3', 627 as => sub { $1 }, 628 629 send => -OTHER, 630 to => 'mp3', 631 632 send => 'debug', 633 to => -ALL, 634 as => 'dump', 635 636 send => -ALL, 637 to => 'logger', 638 ; 639 640=head2 Specifying methods to be delegated 641 642The names of methods to be redispatched can be 643specified using the C<'send'> key. They may be specified as single strings, arrays of strings, regular 644expressions, subroutines, or as one of the two special names: C<-ALL> and C<-OTHER>. 645A single string specifies a single method to be delegated in some way. 646The other alternatives specify sets of methods 647that are to share the associated delegation semantics. That set 648of methods may be specified: 649 650=over 4 651 652=item * 653 654explicitly, by an array (the set consists of those method calls whose names 655appear in the array), 656 657=item * 658 659implicitly, by a regex (the set consists of those method calls whose names match the pattern), 660 661=item * 662 663procedurally, by a subroutine (the set consists of any method calls for which the subroutine 664returns a true value, when passed the method invocant, the method name, and the 665arguments with which the method was invoked), 666 667=item * 668 669generically, by C<-ALL> (the set consists of every method call -- excluding calls 670to C<DESTROY> -- that is not handled by an 671explicit method of the class), 672 673=item * 674 675exclusively, by C<-OTHER> (the set consists of every method call -- excluding calls 676to C<DESTROY> -- that is not successfully 677delegated by any earlier mapping in the C<use Class::Delegation> list). 678 679=back 680 681The exclusion of calls to C<DESTROY> in the last two cases ensures that automatically 682invoked destructor calls are not erroneously delegated. C<DESTROY> calls I<can> be 683delegated through any of the other specification mechanisms. 684 685=head2 Specifying attributes to be delegated to 686 687The actual delegation behaviour is determined by the attributes to which these 688methods are to be delegated. This information can be specified via the C<'to'> 689key, using a string, an array, a regex, a subroutine, or the special flag 690C<-ALL>. Normally the delegated method that is invoked on the specified attribute (or attributes) 691has the same name as the original call, and is invoked in the same calling 692context (void, scalar, or list). 693 694If the attribute is specified via a single string, that string is taken 695as the name of the attribute to which the associated method (or methods) 696should be delegated. For 697example, to delegate invocations of C<$self-E<gt>power(...)> to 698C<$self-E<gt>{flywheel}-E<gt>power(...)>: 699 700 use Class::Delegation 701 send => 'power', 702 to => 'flywheel'; 703 704If the attribute is specified via a single string that starts with C<"->..."> 705then that string is taken as specifying the name of a I<method> of the 706current object. That method is called and is expected to return an 707object. The original method that was being delegated is then delegated to that 708object. For example, to delegate invocations of C<$self-E<gt>power(...)> to 709C<$self-E<gt>flywheel()-E<gt>power(...)>: 710 711 use Class::Delegation 712 send => 'power', 713 to => '->flywheel'; 714 715Since this syntax is a little obscure (and not a little ugly), 716the same effect can also be obtained like so: 717 718 use Class::Delegation 719 send => 'power', 720 to => -SELF->flywheel; 721 722 723An array reference can be used in the attribute position to specify the 724a list of attributes, I<all of which> are delegated to -- in sequence 725they appear in the list. Note that each element of the array is 726processed recursively, so it may contain any of the other attribute 727specifiers described in this section (or, indeed, a nested array of 728attribute specifiers) 729 730For example, to distribute invocations of C<$self-E<gt>drive(...)> to both 731C<$self-E<gt>{left_rear_wheel}-E<gt>drive(...)> and 732 C<$self-E<gt>{right_rear_wheel}-E<gt>drive(...)>: 733 734 use Class::Delegation 735 send => 'drive', 736 to => ["left_rear_wheel", "right_rear_wheel"]; 737 738Note that using an array to specify parallel delegation has an effect on the return 739value of the original method. In a scalar context, the original call returns a reference to 740an array containing the (scalar context) return values of each of the calls. In 741a list context, the original call returns a list of array references 742containing references to the individual (list context) return lists of the calls. So, for example, if a 743class's C<cost> method were delegated like so: 744 745 use Class::Delegation 746 send => 'cost', 747 to => ['supplier', 'manufacturer', 'distributor']; 748 749then the total cost could be calculated like this: 750 751 use List::Util 'sum'; 752 $total = sum @{$obj->cost()}; 753 754Specifying the attribute as a regular expression causes the associated 755method to be delegated to any attribute whose name matches the pattern. 756Attributes are tested for such a match -- and delegated to -- in the 757internal order of their hash (i.e. in the sequence returned by C<keys>). For 758example, to redispatch C<brake> calls to every attribute whose name ends in C<"_wheel">: 759 760 send => 'brake', 761 to => qr/.*_wheel$/, 762 763If a subroutine reference is used as the C<'to'> attribute specifier, it is passed the 764invocant, the name of the method, and the argument list. It is expected to 765return either a value specifying the correct attribute name (or names). As with an 766array, the value returned may be any valid attribute specifier (including 767another subroutine reference) and is iteratively processed to determine the 768correct target(s) for delegation. 769 770A subroutine may also return a reference to an object, in which case the 771subroutine is delegated to that object (rather than to an attribute of 772the current object). This can be useful when the actual delegation target 773is more complex than just a direct attribute. For example: 774 775 send => 'start', 776 to => sub { $_[0]{ignition}{security}[$_[0]->next_key] }, 777 778 779If the C<-ALL> flag is used as the name of the attribute, the method 780is delegated to all attributes of the object (in their C<keys> order). For 781example, to forward debugging requests to every attribute in turn: 782 783 send => 'debug', 784 to => -ALL, 785 786 787=head2 Specifying the name of a delegated method 788 789Sometimes it is necessary to invoke an attribute's method through a 790different name than that of the original delegated method. The C<'as'> 791key facilitates this type of method name translation in any delegation. 792The value associated with an C<'as'> key specifies the name of the 793method to be invoked, and may be a string, an array, or a subroutine. 794 795If a string is provided, it is used as the new name of the delegated method. 796For example, to cause calls to C<$self-E<gt>power(...)> 797to be delegated to C<$self-E<gt>{flywheel}-E<gt>brake(...)>: 798 799 send => 'power', 800 to => 'flywheel', 801 as => 'brake', 802 803If an array is given, it specifies a list of delegated method names. 804If the C<'to'> key specifies a single attribute, each method in the list is 805invoked on that one attribute. For example: 806 807 send => 'boost', 808 to => 'flywheel', 809 as => ['override', 'engage', 'discharge'], 810 811would sequentially call: 812 813 $self->{flywheel}->override(...); 814 $self->{flywheel}->engage(...); 815 $self->{flywheel}->discharge(...); 816 817If both the C<'to'> key and the C<'as'> key specify multiple values, then 818each attribute and method name form a pair, which is invoked. For example: 819 820 send => 'escape', 821 to => ['flywheel', 'smokescreen'], 822 as => ['engage', 'release'], 823 824would sequentially call: 825 826 $self->{flywheel}->engage(...); 827 $self->{smokescreen}->release(...); 828 829If a subroutine reference is used as the C<'as'> specifier, it is passed the 830invocant, the name of the method, and the argument list, and is expected to 831return a string that will be used as the method name. For example, to 832strip method calls of a C<"driver_..."> prefix and delegate them to the 833C<'driver'> attribute: 834 835 send => sub { substr($_[1],0,7) eq "driver_" }, 836 to => 'driver', 837 as => sub { substr($_[1],7) } 838 839or: 840 841 send => qr/driver_(.*)/, 842 to => 'driver', 843 as => sub { $1 } 844 845 846=head2 Delegation to self 847 848Class::Delegation can also be used to delegate methods back to the original 849object, using the C<-SELF> option with the C<'to'> key. For example, to 850redirect any call to C<overdrive> so to invoke the C<boost> method instead: 851 852 send => 'overdrive', 853 to => -SELF, 854 as => 'boost', 855 856Note that this only works if the object I<does not> already have an 857C<overdrive> method. 858 859As with other delegations, a single call can be redelegated-to-self as 860multiple calls. For example: 861 862 send => 'emergency', 863 to => -SELF, 864 as => ['overdrive', 'launch_rockets'], 865 866 867=head2 Handling failure to delegate 868 869If a method cannot be successfully delegated through any of its mappings, 870Class::Delegation will ignore the call and the built-in 871C<AUTOLOAD> mechanism will attempt to handle it instead. 872 873 874=head1 EXAMPLES 875 876Delegation is a useful replacement for inheritance in a number of contexts. 877This section outlines five of the most common uses. 878 879=head2 Simulating single inheritance 880 881Unlike most other OO languages, inheritance in Perl only works well when 882the base class has been I<designed> to be inherited from. If the attributes 883of a prospective base class are inaccessible, or the implementation is 884not extensible (e.g. a blessed scalar or regular expression), or the 885base class's constructor does not use the two-argument form C<bless>, it 886will probably be impractical to inherit from the class. 887 888Moreover, in many cases, it is not possible to tell -- without a detailed 889inspection of a base class's implementation -- whether such a class can easily be 890inherited. This inability to reliably treat classes as encapsulated and 891implementation-independent components seriously undermines the usability 892of object-oriented Perl. 893 894But since inheritance in Perl merely specifies where a class is to look next 895if a suitable method is not found in its own package [3], it is often possible 896to replace derivation with aggregation and use a delegated attribute instead. 897 898For example, it is possible to simulate the inheritance of the class Base 899via a delegated attribute: 900 901 package Derived; 902 use Class::Delegation send => -ALL, to => 'base'; 903 904 sub new { 905 my ($class, $new_attr1, $new_attr2, @base_args) = @_; 906 bless { attr1 => $new_attr1, 907 attr2 => $new_attr2, 908 base => Base->new(@base_args), 909 }, $class; 910 } 911 912Now any method that is not present in Derived is delegated to the Base object 913referred to by the C<base> attribute, just as it would have been if 914Derived actually inherited from Base. 915 916This technique works in situations where the functionality of the Base methods 917is non-polymorphic with respect to their invocant. That is, if an inherited 918method in class Base were to interrogate the class of the object on which it was called, 919it would find a Derived object. But a delegated method in class Base will find a Base object. 920This is not the usual behaviour in OO Perl, but is correct and appropriate under the earlier 921assumption that Base has not been designed to be inherited from -- and must therefore 922always expect a Base class object as its invocant. 923 924 925=head2 Replacing method dispatch semantics 926 927Another situation in which delegation is preferable to inheritance is 928where inheritance I<is> feasible, but Perl's standard dispatch semantics 929-- left-most, depth-first priority of method dispatch -- are 930inappropriate. 931 932For example, if various base classes in a class hierarchy provide a C<dump_info> method 933for debugging purposes, then a derived class than multiply inherits from two or more 934of those classes will only dispatch calls to C<dump_info> to the left-most ancestor's 935method. This is unlikely to be the desired behaviour. 936 937Using delegation it is possible to cause calls to C<dump_info> to invoke the corresponding 938methods of I<all> the base classes, whilst all other method calls are dispatched left-most and 939depth-first, as normal: 940 941 package Derived; 942 use Class::Delegation 943 send => 'dump_info', 944 to => -ALL, 945 946 send => -OTHER, 947 to => 'base1', 948 949 send => -OTHER, 950 to => 'base2', 951 ; 952 953 sub new { 954 my ($class, %named_args) = @_; 955 bless { base1 => Base1->new(%named_args), 956 base2 => Base2->new(%named_args), 957 }, $class; 958 } 959 960Note that the semantics of C<send =E<gt> -OTHER> ensure that only one of the 961two base classes is delegated a method. If C<base1> is able to handle 962a particular method delegation, then it will have been dispatched when 963the C<-OTHER> governing C<base2> is reached, so the second C<-OTHER> will 964ignore it. 965 966 967=head2 Simulating multiple inheritance of pseudohashs 968 969Another situation in which multiple inheritance can cause trouble is 970where a class needs to inherit from two base classes that are both 971implemented via pseudohashes. Because each pseudohash base class will 972assume that I<its> attributes start from index C<1> of the pseudohash 973array, the methods of the two classes would contend for the same 974attribute slots in the derived class. Hence the C<use base> pragma 975detects cases where two ancestral classes are pseudohash-based and 976rejects them (terminally). 977 978Delegation provides a convenient way to provide the effects of 979pseudohash multiple inheritance, without the attendant problems. For example: 980 981 package Derived; 982 use Class::Delegation 983 send => -ALL, 984 to => 'pseudobase1', 985 986 send => -OTHER, 987 to => 'pseudobase2', 988 ; 989 990 sub new { 991 my ($class, %named_args) = @_; 992 bless { pseudobase1 => Pseudo::Base1->new(%named_args), 993 pseudobase2 => Pseudo::Base2->new(%named_args), 994 }, $class; 995 } 996 997As in the previous example, only one of the two base classes 998is delegated a method. The C<-ALL> associated with C<pseudobase1> 999attempts to delegate every method to that attribute, then the C<-OTHER> 1000associated with C<pseudobase2> catches any methods that cannot be 1001handled by C<pseudobase1>. 1002 1003 1004 1005=head2 Adapting legacy code 1006 1007Because the C<'as'> key can take a subroutine, it is also possible to 1008use a delegating class to adapt the interface of an existing class. For example, 1009a class with separate "get" and "set" accessors: 1010 1011 class DogTag; 1012 1013 sub get_name { return $_[0]->{name} } 1014 sub set_name { $_[0]->{name} = $_[1] } 1015 1016 sub get_rank { return $_[0]->{rank} } 1017 sub set_rank { $_[0]->{rank} = $_[1] } 1018 1019 sub get_serial { return $_[0]->{serial} } 1020 sub set_serial { $_[0]->{serial} = $_[1] } 1021 1022 # etc. 1023 1024could be trivially adapted to provide combined get/set accessors like so: 1025 1026 class DogTag::SingleAccess; 1027 1028 use Class::Delegation 1029 send => -ALL 1030 to => 'dogtag', 1031 as => sub { 1032 my ($invocant, $method, @args) = @_; 1033 return @args ? "set_$method" : "get_$method" 1034 }, 1035 ; 1036 1037 sub new { bless { dogtag => DogTag->new(@_[1..$#_) }, $_[0] } 1038 1039Here, the C<'as'> subroutine determines whether an "new value" argument 1040was passed to the original method, delegating to the C<set_...> method if so, 1041and to the C<get_...> method otherwise. 1042 1043 1044=head2 Multiplexing a facade 1045 1046The ability to use regular expressions to specify method names, and 1047subroutines to indicate the attributes and attribute methods to which 1048they are delegated, opens the possibility of creating a class that 1049acts as a collective front-end for several others. For example: 1050 1051 package Bilateral; 1052 1053 %Bilateral = ( left => 'Levorotatory', 1054 right => 'Dextrorotatory', 1055 ); 1056 1057 use Class::Delegation 1058 send => qr/(left|right)_(.*)/, 1059 to => sub { $1 }, 1060 as => sub { $2 }, 1061 ; 1062 1063 sub AUTOLOAD { 1064 carp "$AUTOLOAD does not begin with 'left_...' or 'right_...'" 1065 }, 1066 1067 1068The Bilateral class now forwards all I<class> method calls that are prefixed 1069with C<"left_..."> to the Laevorotatory class, and all those prefixed with 1070C<"right_..."> to the Dextrorotatory class. Any calls that cannot be dispatched 1071are caught and ignored (with a warning) by the C<AUTOLOAD>. 1072 1073The mechanism by which the class method dispatch is achieved is perhaps a little obscure. 1074Consider the invocation of a class method: 1075 1076 Bilateral->left_rotate(45); 1077 1078Here, the invocant is the string C<"Bilateral">, rather than a blessed object. Thus, 1079when Class::Delegation forwards the call to: 1080 1081 $self->{$1}->$2(45); 1082 1083the effect is the same as calling: 1084 1085 "Bilateral"->{left}->rotate(45); 1086 1087This invokes a little-known feature of the C<-E<gt>> operator [4]. If a hash access is 1088performed on a string, that string is taken as a symbolic 1089reference to a package hash variable in the current package. Thus the above call is internally translated to: 1090 1091 ${"Bilateral"}{left}->rotate(45); 1092 1093which is equivalent to the class method call: 1094 1095 Levorotatory->rotate(45); 1096 1097=head1 AUTHOR 1098 1099Damian Conway (damian@conway.org) 1100 1101=head1 BUGS 1102 1103There are undoubtedly serious bugs lurking somewhere in this code. 1104Bug reports and other feedback are most welcome. 1105 1106=head1 COPYRIGHT 1107 1108 Copyright (c) 2001, Damian Conway. All Rights Reserved. 1109 This module is free software. It may be used, redistributed 1110 and/or modified under the same terms as Perl itself. 1111