File Coverage

blib/lib/Sub/MultiMethod.pm
Criterion Covered Total %
statement 329 357 92.1
branch 108 136 79.4
condition 44 68 64.7
subroutine 50 52 96.1
pod 11 13 84.6
total 542 626 86.5


line stmt bran cond sub pod time code
1 11     11   1181438 use 5.008001;
  11         108  
2 11     11   46 use strict;
  11         16  
  11         194  
3 11     11   46 use warnings;
  11         16  
  11         541  
4              
5              
6             our $AUTHORITY = 'cpan:TOBYINK';
7             our $VERSION = '0.908';
8              
9             use B ();
10 11     11   54 use Exporter::Shiny qw(
  11         17  
  11         248  
11 11         55 multimethod monomethod
12             multifunction monofunction
13             multimethods_from_roles
14             );
15 11     11   3648 use Role::Hooks;
  11         15775  
16 11     11   4473 use Scalar::Util qw( refaddr );
  11         46000  
  11         314  
17 11     11   71 use Type::Params ();
  11         15  
  11         418  
18 11     11   4881 use Types::Standard qw( -types -is );
  11         393538  
  11         289  
19 11     11   63  
  11         21  
  11         68  
20             *_set_subname =
21             eval { require Sub::Util; \&Sub::Util::set_subname } ||
22             eval { require Sub::Name; \&Sub::Name::subname } ||
23             do { sub { pop } } ;
24              
25             {
26             my %CANDIDATES;
27             my ($me, $target) = @_;
28             if ( not $CANDIDATES{$target} ) {
29 371     371   470 $CANDIDATES{$target} = {};
30 371 100       609 }
31 33         64 $CANDIDATES{$target};
32             }
33 371         551 }
34              
35             my ($me, $target) = @_;
36             sort keys %{ $me->_get_multimethods_ref($target) };
37             }
38 17     17 1 27  
39 17         20 my ($me, $target, $method_name) = @_;
  17         30  
40             my ( $package_key, $method_key ) = ref( $method_name )
41             ? ( '__CODE__', refaddr( $method_name ) )
42             : ( $target, $method_name );
43 351     351   439 my $mm = $me->_get_multimethods_ref( $package_key );
44 351 100       596 $mm->{$method_key} ||= [];
45             }
46              
47 351         527 my ( $me, $target, $method_name ) = ( shift, @_ );
48 351   100     892 my ( $package_key, $method_key ) = ref( $method_name )
49             ? ( '__CODE__', refaddr( $method_name ) )
50             : ( $target, $method_name );
51             my $mm = $me->_get_multimethods_ref( $package_key );
52 2     2   5 delete $mm->{$method_key};
53 2 50       5 return $me;
54             }
55            
56 2         5 my ($me, $target, $method_name) = @_;
57 2         3 @{ $me->_get_multimethod_candidates_ref($target, $method_name) };
58 2         4 }
59              
60             my ($me, $target, $method_name) = @_;
61             scalar @{ $me->_get_multimethod_candidates_ref($target, $method_name) };
62 101     101 1 155 }
63 101         118  
  101         139  
64             my ($me, $target, $method_name, $spec) = @_;
65             my $mmc = $me->_get_multimethod_candidates_ref($target, $method_name);
66             if ( @$mmc and $spec->{method} != $mmc->[0]{method} ) {
67 139     139 1 210 require Carp;
68 139         148 Carp::carp(sprintf(
  139         217  
69             "Added multimethod candidate for %s with method=>%d but expected method=>%d",
70             $method_name,
71             $spec->{method},
72 111     111   176 $mmc->[0]{method},
73 111         210 ));
74 111 50 66     335 }
75 0         0 push @$mmc, $spec;
76             $me;
77             }
78              
79             my ($me, $target, $method_name, $is_method) = @_;
80            
81 0         0 # Figure out which packages to consider when finding candidates.
82             my (@packages, $is_coderef_method);
83 111         168 if (is_Int $method_name or is_ScalarRef $method_name) {
84 111         165 @packages = '__CODE__';
85             $is_coderef_method = 1;
86             }
87             else {
88 59     59 1 121 @packages = $is_method
89             ? @{ mro::get_linear_isa($target) }
90             : $target;
91 59         74 }
92 59 100 66     250
93 11         16 my $curr_height = @packages;
94 11         15
95             # Find candidates from each package
96             my @candidates;
97             my $final_fallback = undef;
98 48 100       84 PACKAGE: while (@packages) {
  46         152  
99             my $p = shift @packages;
100             my @c;
101             my $found = $me->has_multimethod_candidates($p, $method_name);
102 59         85 if ($found) {
103             @c = $me->get_multimethod_candidates($p, $method_name);
104             }
105 59         90 elsif (not $is_coderef_method) {
106 59         78 no strict 'refs';
107 59         134 if (exists &{"$p\::$method_name"}) {
108 139         172 # We found a potential monomethod.
109 139         182 my $coderef = \&{"$p\::$method_name"};
110 139         234 if (!$me->known_dispatcher($coderef)) {
111 139 100       236 # Definite monomethod. Stop falling back.
    50          
112 84         165 $final_fallback = $coderef;
113             last PACKAGE;
114             }
115 11     11   87749 }
  11         31  
  11         12627  
116 55 100       65 @c = ();
  55         190  
117             }
118 8         9 # Record their height in case we need it later
  8         17  
119 8 50       14 $_->{height} = $curr_height for @c;
120             push @candidates, @c;
121 8         11 --$curr_height;
122 8         17 }
123            
124             # If a monomethod was found, use it as last resort
125 47         59 if (defined $final_fallback) {
126             push @candidates, {
127             signature => sub { @_ },
128 131         322 code => $final_fallback,
129 131         184 };
130 131         281 }
131            
132             return @candidates;
133             }
134 59 100       110  
135             {
136 8     8   18 my %DISPATCHERS;
137 8         33
138             my ($me, $coderef) = @_;
139             $DISPATCHERS{refaddr($coderef)};
140             }
141 59         200
142             my ($me, $coderef) = @_;
143             $DISPATCHERS{refaddr($coderef)} = 1;
144             $me;
145             }
146            
147             my ($me, $coderef) = @_;
148 31     31 1 57 $DISPATCHERS{refaddr($coderef)} = 0;
149 31         118 $me;
150             }
151             }
152              
153 23     23   43 my ($me, $name, $args, $globals) = (shift, @_);
154 23         73 return sub {
155 23         31 require Carp;
156             Carp::carp( "Calling multimethods_from_roles is no longer needed and the function will be removed in a future release. Called" );
157             };
158             }
159 0     0   0  
160 0         0 my ( $me, $name, $args, $globals ) = ( shift, @_ );
161 0         0
162             my $target = $globals->{into};
163             if ( ref $target or not defined $target ) {
164             require Carp;
165             Carp::croak( "Function $name can only be installed into a package by package name" );
166 4     4   162 }
167            
168 0     0   0 my %defaults = %{ $args->{defaults} || {} };
169 0         0 my $api_call = $args->{api_call} || 'install_candidate';
170 4         15
171             return sub {
172             my ( $sub_name, %spec ) = @_;
173             if ( $defaults{no_dispatcher} eq 'auto' ) {
174 36     36   61 $defaults{no_dispatcher} = 0+!! 'Role::Hooks'->is_role( $target );
175             }
176 36         50 $me->$api_call(
177 36 50 33     150 $target,
178 0         0 $sub_name,
179 0         0 %defaults,
180             %spec,
181             );
182 36 50       47 };
  36         134  
183 36   100     102 }
184              
185             my ( $me, $name, $args, $globals ) = ( shift, @_ );
186 51     51   15103 $args->{defaults}{no_dispatcher} = 'auto';
187 51 100       164 return $me->_generate_exported_function( $name, $args, $globals );
188 22         90 }
189              
190 51         466 my ( $me, $name, $args, $globals ) = ( shift, @_ );
191             $args->{defaults}{no_dispatcher} = 1;
192             $args->{api_call} = 'install_monomethod';
193             return $me->_generate_exported_function( $name, $args, $globals );
194             }
195              
196 36         228 my ( $me, $name, $args, $globals ) = ( shift, @_ );
197             $args->{defaults}{no_dispatcher} = 'auto';
198             $args->{defaults}{method} = 0;
199             return $me->_generate_exported_function( $name, $args, $globals );
200 22     22   51888 }
201 22         62  
202 22         52 my ( $me, $name, $args, $globals ) = ( shift, @_ );
203             $args->{defaults}{no_dispatcher} = 1;
204             $args->{defaults}{method} = 0;
205             $args->{api_call} = 'install_monomethod';
206 5     5   337 return $me->_generate_exported_function( $name, $args, $globals );
207 5         11 }
208 5         10  
209 5         8 my %keep_while_copying = qw(
210             method 1
211             declaration_order 1
212             signature 1
213 5     5   313 code 1
214 5         10 score 1
215 5         9 named 1
216 5         12 );
217             my $me = shift;
218             my (@sources) = @_;
219             my $target = pop @sources;
220 4     4   160
221 4         8 for my $source (@sources) {
222 4         4 for my $method_name ($me->get_multimethods($source)) {
223 4         6 for my $candidate ($me->get_multimethod_candidates($source, $method_name)) {
224 4         6 my %new = map {
225             $keep_while_copying{$_}
226             ? ( $_ => $candidate->{$_} )
227             : ()
228             } keys %$candidate;
229             $new{copied} = 1;
230             $me->_add_multimethod_candidate($target, $method_name, \%new);
231             }
232             }
233             }
234             }
235              
236 10     10 1 14 my $me = shift;
237 10         17 my ($target) = @_;
238 10         13
239             for my $method_name ($me->get_multimethods($target)) {
240 10         19 my ($first) = $me->get_multimethod_candidates($target, $method_name);
241 10         17 $me->install_dispatcher(
242 10         20 $target,
243             $method_name,
244 64         117 $first ? $first->{'method'} : 0,
245 321 100       575 );
246             }
247             }
248 64         105  
249 64         95 my $me = shift;
250             my ($target, $sub_name, %spec) = @_;
251            
252             $spec{alias} ||= [];
253             $spec{alias} = [$spec{alias}] if !ref $spec{alias};
254             unshift @{$spec{alias}}, $sub_name;
255            
256 7     7 1 124 $me->install_candidate($target, undef, no_dispatcher => 1, %spec, is_monomethod => 1);
257 7         13 }
258              
259 7         15 my %hooked;
260 7         15 my $DECLARATION_ORDER = 0;
261             my $me = shift;
262             my ($target, $sub_name, %spec) = @_;
263             $spec{method} = 1 unless defined $spec{method};
264 7 50       23  
265             my $is_method = $spec{method};
266            
267             $spec{declaration_order} = ++$DECLARATION_ORDER;
268            
269             $me->_add_multimethod_candidate($target, $sub_name, \%spec)
270 2     2 1 4 if defined $sub_name;
271 2         7
272             if ($spec{alias}) {
273 2   50     11 $spec{alias} = [$spec{alias}] unless is_ArrayRef $spec{alias};
274 2 50       5 my @aliases = @{$spec{alias}};
275 2         3 my $next = $spec{code} or die "NO CODE???";
  2         4  
276            
277 2         10 my ($check, @sig);
278             if (is_CodeRef $spec{signature}) {
279             $check = $spec{signature};
280             }
281             else {
282             @sig = @{$spec{signature}};
283 51     51 1 73 if (is_HashRef $sig[0] and not $sig[0]{slurpy}) {
284 51         136 my %new_opts = %{$sig[0]};
285 51 100       127 delete $new_opts{want_source};
286             delete $new_opts{want_details};
287 51         68 $sig[0] = \%new_opts;
288             }
289 51         74 }
290            
291 51 100       155 my $code = sprintf(
292             q{
293             package %s;
294 51 100       98 sub {
295 8 100       39 my @invocants = splice(@_, 0, %d);
296 8         13 $check ||= %s(@sig);
  8         18  
297 8 50       23 @_ = (@invocants, &$check);
298             goto $next;
299 8         17 }
300 8 50       26 },
301 0         0 $target,
302             $spec{method},
303             $spec{named}
304 8         12 ? 'Type::Params::compile_named_oo'
  8         19  
305 8 50 33     30 : 'Type::Params::compile',
306 0         0 );
  0         0  
307 0         0 my $coderef = do {
308 0         0 local $@;
309 0         0 eval $code or die $@,
310             };
311             for my $alias (@aliases) {
312             my $existing = do {
313             no strict 'refs';
314             exists(&{"$target\::$alias"})
315             ? \&{"$target\::$alias"}
316             : undef;
317             };
318             if ($existing) {
319             my $kind = ($spec{is_monomethod} && ($alias eq $aliases[0]))
320             ? 'Monomethod'
321             : 'Alias';
322             require Carp;
323             Carp::croak("$kind conflicts with existing method $target\::$alias, bailing out");
324             }
325             $me->_install_coderef( $target, $alias, $coderef );
326 8 50       50 }
327             }
328            
329 8         13 $me->install_dispatcher($target, $sub_name, $is_method)
330 8         13 if defined $sub_name && !$spec{no_dispatcher};
331 8 50 66 28   791
  24     5   9047  
  24         102  
  24         4126  
  16         1101  
332             if ( !$hooked{$target} and 'Role::Hooks'->is_role($target) ) {
333 8         20 'Role::Hooks'->after_apply($target, sub {
334 8         14 my ($rolepkg, $consumerpkg) = @_;
335 11     11   78 $me->copy_package_candidates($rolepkg => $consumerpkg);
  11         27  
  11         4363  
336 8         43 $me->install_missing_dispatchers($consumerpkg)
337 8 100       11 unless 'Role::Hooks'->is_role($consumerpkg);
  2         8  
338             });
339             $hooked{$target}++;
340 8 100       20 }
341 2 100 66     21 }
342              
343             {
344 2         9 my %CLEANUP;
345 2         315
346             my $me = shift;
347 6         27 my ($target, $sub_name, $coderef) = @_;
348             if (is_ScalarRef $sub_name) {
349             if (is_Undef $$sub_name) {
350             _set_subname("$target\::__ANON__", $coderef);
351             bless( $coderef, $me );
352 49 100 100     210 $CLEANUP{"$coderef"} = [ $target, refaddr($sub_name) ];
353             return( $$sub_name = $coderef );
354 47 100 100     173 }
355             elsif (is_CodeRef $$sub_name or is_Object $$sub_name) {
356 10     10   2568 if ( $me->known_dispatcher($$sub_name) ) {
357 10         24 return $$sub_name;
358 10 100       27 }
359             else {
360 5         76 require Carp;
361 5         744 Carp::croak(sprintf(
362             'Sub name was a reference to an unknown coderef or object: %s',
363             $$sub_name,
364             ));
365             }
366             }
367             }
368             elsif (is_Str $sub_name) {
369 29     29   52 no strict 'refs';
370 29         375 my $qname = "$target\::$sub_name";
371 29 100       141 *$qname = _set_subname($qname, $coderef);
    50          
372 7 100 33     31 return $coderef;
    50          
373 2         12 }
374 2         5 require Carp;
375 2         12 Carp::croak(sprintf(
376 2         6 'Expected string or reference to coderef as sub name, but got: %s %s',
377             $sub_name,
378             ));
379 5 50       11 }
380 5         10
381             my $blessed_coderef = shift;
382             my ( $target, $sub_name ) = @{ $CLEANUP{"$blessed_coderef"} or [] };
383 0         0 if ( $target and $sub_name ) {
384 0         0 $blessed_coderef->_clear_multimethod_candidates_ref($target, $sub_name);
385             }
386             return;
387             }
388             }
389              
390             my $me = shift;
391             my ($target, $sub_name, $is_method) = @_;
392 11     11   73
  11         18  
  11         2126  
393 22         81 exists &mro::get_linear_isa
394 22         183 or eval { require mro }
395 22         66 or do { require MRO::Compat };
396            
397 0         0 my $existing = do {
398 0         0 no strict 'refs';
399             exists(&{"$target\::$sub_name"})
400             ? \&{"$target\::$sub_name"}
401             : undef;
402             };
403            
404             return if !defined $sub_name;
405 2     2   987
406 2 50       2 if ($existing and $me->known_dispatcher($existing)) {
  2         10  
407 2 50 33     10 return $me; # already installed
408 2         5 }
409             elsif ($existing) {
410 2         24 require Carp;
411             Carp::croak("Multimethod conflicts with monomethod $target\::$sub_name, bailing out");
412             }
413            
414             my $code = sprintf(
415 41     41 1 57 q{
416 41         68 package %s;
417             sub {
418             my $next = %s->can('dispatch');
419 0         0 @_ = (%s, %s, %s, %d, [@_]);
420 41 50 33     106 goto $next;
  0         0  
421             }
422 41         47 },
423 11     11   83 $target, # package %s
  11         24  
  11         7075  
424 41         169 B::perlstring($me), # %s->can('dispatch')
425 41 100       46 B::perlstring($me), # $_[0]
  18         45  
426             B::perlstring($target), # $_[1]
427             ref($sub_name) # $_[2]
428             ? refaddr($sub_name)
429 41 50       79 : B::perlstring("$sub_name"),
430             $is_method, # $_[3]
431 41 100 100     140 );
    100          
432 16         41
433             my $coderef = do {
434             local $@;
435 2         10 eval $code or die $@;
436 2         251 };
437            
438             $me->_install_coderef($target, $sub_name, $coderef);
439 23 100       245 $me->_mark_as_dispatcher($coderef);
440             return $coderef;
441             }
442              
443             my $me = shift;
444             my ($pkg, $method_name, $is_method, $argv) = @_;
445            
446             # Steal invocants because we don't want them to be considered
447             # as part of the signature.
448             my @invocants;
449             push @invocants, splice(@$argv, 0, $is_method);
450            
451             if ( $is_method and is_Object($invocants[0]) ) {
452             # object method; reset package search from invocant class
453             $pkg = ref($invocants[0]);
454             }
455             elsif ( $is_method and is_ClassName($invocants[0]) ) {
456             # class method; reset package search from invocant class
457             $pkg = $invocants[0];
458 23         43 }
459 23         28
460 23 50   7   2044 my ($winner, $new_argv, $new_invocants) = $me->pick_candidate(
  2         7  
  2         6  
461             [ $me->get_all_multimethod_candidates($pkg, $method_name, $is_method) ],
462             $argv,
463 23         89 \@invocants,
464 23         56 ) or do {
465 23         70 require Carp;
466             Carp::croak('Multimethod could not find candidate to dispatch to, stopped');
467             };
468            
469 78     78 0 5526 my $next = $winner->{code};
470 78         173 @_ = (@$new_invocants, @$new_argv);
471             goto $next;
472             }
473              
474 78         128 # Type which when given \@_ determines if it could potentially
475 61         1109 # be named parameters.
476             #
477 61 100 100     295 my $Named = CycleTuple->of(Str, Any) | Tuple->of(HashRef);
    100 100        
478              
479 41         103 my $me = shift;
480             my ($candidates, $argv, $invocants) = @_;
481            
482             my @remaining = @{ $candidates };
483 10         2340
484             # Compile signatures into something useful. (Cached.)
485             #
486            
487             for my $candidate (@remaining) {
488             next if $candidate->{compiled};
489             if (is_CodeRef $candidate->{signature}) {
490 64 100       189 $candidate->{compiled}{closure} = $candidate->{signature};
491 8         31 $candidate->{compiled}{min_args} = 0;
492 7         1988 $candidate->{compiled}{max_args} = undef;
493             }
494             else {
495 60         144 my @sig = @{ $candidate->{signature} };
496 60         123 my $opt = (is_HashRef $sig[0] and not $sig[0]{slurpy})
497 61         1893 ? shift(@sig)
498             : {};
499             $opt->{want_details} = 1;
500            
501             $candidate->{compiled} = $candidate->{named}
502             ? Type::Params::compile_named_oo($opt, @sig)
503             : Type::Params::compile($opt, @sig);
504            
505             $candidate->{compiled}{_pure_named} = $candidate->{named};
506 64     61 1 98 delete $candidate->{compiled}{_pure_named}
507 64         107 if $opt->{head} || $opt->{tail};
508             }
509 64         2173 }
  64         140  
510            
511             # Weed out signatures that cannot match because of
512             # argument count.
513             #
514 64         114
515 372 100       594 my $argc = @$argv;
516 87 100       230 my $argv_maybe_named = $Named->check($argv);
517 8         15
518 8         12 @remaining = grep {
519 8         14 my $candidate = $_;
520             if ($candidate->{compiled}{_pure_named} && !$argv_maybe_named) {
521             0;
522 79         93 }
  79         172  
523             elsif (defined $candidate->{compiled}{min_args} and $candidate->{compiled}{min_args} > $argc) {
524 79 100 66     248 0;
525             }
526 79         129 elsif (defined $candidate->{compiled}{max_args} and $candidate->{compiled}{max_args} < $argc) {
527             0;
528             }
529 79 100       221 else {
530             1;
531             }
532 79         61911 } @remaining;
533            
534 79 100 66     428
535             # Weed out signatures that cannot match because
536             # they fail type checks, etc
537             #
538            
539             my %returns;
540            
541             @remaining = grep {
542 59         93 my $code = $_->{compiled}{closure};
543 59         193 eval {
544             $returns{"$code"} = [ $code->(@$argv) ];
545             1;
546 59         6477 };
  372         384  
547 372 50 33     1560 } @remaining;
    100 66        
    100 100        
548 0         0
549             # Various techniques to cope with @remaining > 1...
550             #
551 7         14
552             if (@remaining > 1) {
553             no warnings qw(uninitialized numeric);
554 2         5 # Calculate signature constrainedness score. (Cached.)
555             for my $candidate (@remaining) {
556             next if defined $candidate->{score};
557 363         543 my $sum = 0;
558             if (is_ArrayRef $candidate->{signature}) {
559             foreach my $type (@{ $candidate->{signature} }) {
560             next unless is_Object $type;
561             my @real_parents = grep !$_->_is_null_constraint, $type, $type->parents;
562             $sum += @real_parents;
563             }
564             }
565             $candidate->{score} = $sum;
566 59         81 }
567             # Only keep those with (equal) highest score
568             @remaining = sort { $b->{score} <=> $a->{score} } @remaining;
569 59         79 my $max_score = $remaining[0]->{score};
  363         51678  
570 363         463 @remaining = grep { $_->{score} == $max_score } @remaining;
571 363         663 }
572 108         1094
573             if (@remaining > 1) {
574             # Only keep those from the most derived class
575             no warnings qw(uninitialized numeric);
576             @remaining = sort { $b->{height} <=> $a->{height} } @remaining;
577             my $max_score = $remaining[0]->{height};
578             @remaining = grep { $_->{height} == $max_score } @remaining;
579 59 100       8979 }
580 11     11   73
  11         19  
  11         1849  
581             if (@remaining > 1) {
582 28         58 # Only keep those from the most non-role-like packages
583 80 100       152 no warnings qw(uninitialized numeric);
584 37         49 @remaining = sort { $a->{copied} <=> $b->{copied} } @remaining;
585 37 100       94 my $min_score = $remaining[0]->{copied};
586 33         40 @remaining = grep { $_->{copied} == $min_score } @remaining;
  33         56  
587 48 50       118 }
588 48         95
589 48         2527 if (@remaining > 1) {
590             # Argh! Still got multiple candidates! Just choose whichever
591             # was declared first...
592 37         95 no warnings qw(uninitialized numeric);
593             @remaining = sort { $a->{declaration_order} <=> $b->{declaration_order} } @remaining;
594             @remaining = ($remaining[0]);
595 28         86 }
  90         137  
596 28         42
597 28         49 # This is filled in each call. Clean it up, just in case.
  80         149  
598             delete $_->{height} for @$candidates;
599            
600 59 100       127 wantarray or die 'MUST BE CALLED IN LIST CONTEXT';
601            
602 11     11   70 return unless @remaining;
  11         17  
  11         799  
603 10         18
  28         43  
604 10         14 my $sig_code = $remaining[0]{compiled}{closure};
605 10         16 return ( $remaining[0], $returns{"$sig_code"}, $invocants||[] );
  29         50  
606             }
607              
608 59 100       106 no warnings qw(uninitialized numeric);
609             my $candidate = shift;
610 11     11   64 my $types_etc = join ",", map "$_", @{$candidate->{signature}};
  11         22  
  11         822  
611 5         11 my $r = sprintf('%s:%s', $candidate->{named} ? 'NAMED' : 'POSITIONAL', $types_etc);
  23         32  
612 5         8 $r .= sprintf('{score:%d+%d}', $candidate->{score}, $candidate->{height})
613 5         9 if defined($candidate->{score})||defined($candidate->{height});
  19         33  
614             return $r;
615             }
616 59 100       105  
617             1;
618              
619 11     11   72  
  11         19  
  11         2380  
620 4         8 =pod
  22         27  
621 4         7  
622             =encoding utf-8
623              
624             =head1 NAME
625 59         211  
626             Sub::MultiMethod - yet another implementation of multimethods
627 59 50       102  
628             =head1 SYNOPSIS
629 59 100       110  
630             How to generate JSON (albeit with very naive string quoting) using
631 56         83 multimethods:
632 56   50     285  
633             use v5.12;
634             use strict;
635             use warnings;
636 11     11   86
  11         21  
  11         1714  
637 0     5 0 0 package My::JSON {
638 0         0 use Moo;
  0         0  
639 0 0       0 use Sub::MultiMethod qw(multimethod);
640             use Types::Standard -types;
641 0 0 0     0
642 0         0 multimethod stringify => (
643             signature => [ Undef ],
644             code => sub {
645             my ($self, $undef) = (shift, @_);
646             'null';
647             },
648             );
649            
650             multimethod stringify => (
651             signature => [ ScalarRef[Bool] ],
652             code => sub {
653             my ($self, $bool) = (shift, @_);
654             $$bool ? 'true' : 'false';
655             },
656             );
657            
658             multimethod stringify => (
659             alias => "stringify_str",
660             signature => [ Str ],
661             code => sub {
662             my ($self, $str) = (shift, @_);
663             sprintf(q<"%s">, quotemeta($str));
664             },
665             );
666            
667             multimethod stringify => (
668             signature => [ Num ],
669             code => sub {
670             my ($self, $n) = (shift, @_);
671             $n;
672             },
673             );
674            
675             multimethod stringify => (
676             signature => [ ArrayRef ],
677             code => sub {
678             my ($self, $arr) = (shift, @_);
679             sprintf(
680             q<[%s]>,
681             join(q<,>, map($self->stringify($_), @$arr))
682             );
683             },
684             );
685            
686             multimethod stringify => (
687             signature => [ HashRef ],
688             code => sub {
689             my ($self, $hash) = (shift, @_);
690             sprintf(
691             q<{%s}>,
692             join(
693             q<,>,
694             map sprintf(
695             q<%s:%s>,
696             $self->stringify_str($_),
697             $self->stringify($hash->{$_})
698             ), sort keys %$hash,
699             )
700             );
701             },
702             );
703             }
704            
705             my $json = My::JSON->new;
706            
707             say $json->stringify({
708             foo => 123,
709             bar => [1,2,3],
710             baz => \1,
711             quux => { xyzzy => 666 },
712             });
713              
714             =head1 DESCRIPTION
715              
716             Sub::Multimethod focusses on implementing the dispatching of multimethods
717             well and is less concerned with providing a nice syntax for setting them
718             up. That said, the syntax provided is inspired by Moose's C<has> keyword
719             and hopefully not entirely horrible.
720              
721             Sub::MultiMethod has much smarter dispatching than L<Kavorka>, but the
722             tradeoff is that this is a little slower. Overall, for the JSON example
723             in the SYNOPSIS, Kavorka is about twice as fast. (But with Kavorka, it
724             would quote the numbers in the output because numbers are a type of string,
725             and that was declared first!)
726              
727             =head2 Functions
728              
729             Sub::MultiMethod exports nothing by default. You can import the functions
730             you want by listing them in the C<use> statement:
731              
732             use Sub::MultiMethod "multimethod";
733              
734             You can rename functions:
735              
736             use Sub::MultiMethod "multimethod" => { -as => "mm" };
737              
738             You can import everything using C<< -all >>:
739              
740             use Sub::MultiMethod -all;
741              
742             Sub::MultiMethod also offers an API for setting up multimethods for a
743             class, in which case, you don't need to import anything.
744              
745             =head3 C<< multimethod $name => %spec >>
746              
747             The following options are supported in the specification for the
748             multimethod.
749              
750             =over
751              
752             =item C<< named >> I<< (Bool) >>
753              
754             Optional, defaults to false.
755              
756             Indicates whether this candidate uses named parameters. The default is
757             positional parameters.
758              
759             =item C<< signature >> I<< (ArrayRef|CodeRef) >>
760              
761             Required.
762              
763             For positional parameters, an ordered list of type constraints suitable
764             for passing to C<compile> from L<Type::Params>.
765              
766             signature => [ Str, RegexpRef, Optional[FileHandle] ],
767              
768             For named parameters, a list suitable for passing to C<compile_named_oo>.
769              
770             signature => [
771             prefix => Str,
772             match => RegexpRef,
773             output => FileHandle, { default => sub { \*STDOUT } },
774             ],
775              
776             Sub::MultiMethods is designed to handle multi I<methods>, so C<< $self >>
777             at the start of all signatures is implied.
778              
779             C<signature> I<may> be a coderef instead, which should die if it gets
780             passed a C<< @_ >> that it cannot handle, or return C<< @_ >> (perhaps
781             after some processing) if it is successful. Using coderef signatures
782             may make deciding which candidate to dispatch to more difficult though,
783             in cases where more than one candidate matches the given parameters.
784              
785             =item C<< code >> I<< (CodeRef) >>
786              
787             Required.
788              
789             The sub to dispatch to. It will receive parameters in C<< @_ >> as you
790             would expect, but these parameters have been passed through the signature
791             already, so will have had defaults and coercions applied.
792              
793             An example for positional parameters:
794              
795             code => sub {
796             my ($self, $prefix, $match, $output) = (shift, @_);
797             print {$output} $prefix;
798             ...;
799             },
800              
801             An example for named parameters:
802              
803             code => sub {
804             my ($self, $arg) = (shift, @_);
805             print {$arg->output} $arg->prefix;
806             ...;
807             },
808              
809             Note that C<< $arg >> is an object with methods for each named parameter.
810              
811             =item C<< alias >> I<< (Str|ArrayRef[Str]) >>
812              
813             Optional.
814              
815             Installs an alias for the candidate, bypassing multimethod dispatch. (But not
816             bypassing the checks, coercions, and defaults in the signature!)
817              
818             =item C<< method >> I<< (Int) >>
819              
820             Optional, defaults to 1.
821              
822             Indicates whether the multimethod should be treated as a method (i.e. with an
823             implied C<< $self >>). Defaults to true, but C<< method => 0 >> can be
824             given if you want multifuncs with no invocant.
825              
826             Multisubs where some candidates are methods and others are non-methods are
827             not currently supported! (And probably never will be.)
828              
829             (Yes, this is technically an integer rather than a boolean. This allows
830             for subs to have, say, two logical invocants. For example, in Catalyst,
831             you might want to treat the context object as a second invocant.)
832              
833             =item C<< score >> I<< (Int) >>
834              
835             Optional.
836              
837             Overrides the constrainedness score calculated as described in the dispatch
838             technique. Most scores calculated that way will typically between 0 and 100.
839             Setting a score manually to something very high (e.g. 9999) will pretty much
840             guarantee that it gets chosen over other candidates when multiple signatures
841             match. Setting it to something low (e.g. -1) will mean it gets avoided.
842              
843             =item C<< no_dispatcher >> I<< (Bool) >>
844              
845             Optional. Defaults to true in roles, false otherwise.
846              
847             If set to true, Sub::MultiMethods will register the candidate method
848             but won't install a dispatcher. You should mostly not worry about this
849             and accept the default.
850              
851             =back
852              
853             =head3 C<< monomethod $name => %spec >>
854              
855             As a convenience, you can use Sub::MultiMethod to install normal methods.
856             Why do this instead of using Perl's plain old C<sub> keyword? Well, it gives
857             you the same signature checking.
858              
859             Supports the following options:
860              
861             =over
862              
863             =item C<< named >> I<< (Bool) >>
864              
865             =item C<< signature >> I<< (ArrayRef|CodeRef) >>
866              
867             =item C<< code >> I<< (CodeRef) >>
868              
869             =item C<< method >> I<< (Int) >>
870              
871             =back
872              
873             C<< monomethod($name, %spec) >> is basically just a shortcut for
874             C<< multimethod(undef, alias => $name, %spec) >> though with error
875             messages which don't mention it being an alias.
876              
877             =head3 C<< multifunction $name => %spec >>
878              
879             Like C<multimethod> but defaults to C<< method => 0 >>.
880              
881             =head3 C<< monofunction $name => %spec >>
882              
883             Like C<monomethod> but defaults to C<< method => 0 >>.
884              
885             =head2 Dispatch Technique
886              
887             When a multimethod is called, a list of packages to inspect for candidates
888             is obtained by crawling C<< @ISA >>. (For multifuncs, C<< @ISA >> is ignored.)
889              
890             All candidates for the invoking class and all parent classes are considered.
891              
892             If any parent class includes a mono-method (i.e. not a multimethod) of the
893             same name as this multimethod, then it is considered to have override any
894             candidates further along the C<< @ISA >> chain. (With multiple inheritance,
895             this could get confusing though!) Those further candidates will not be
896             considered, however the mono-method will be considered to be a candidate,
897             albeit one with a very low score. (See scoring later.)
898              
899             Any candidates where it is clear they will not match based on parameter
900             count will be discarded immediately.
901              
902             After that, the signatures of each are tried. If they throw an error, that
903             candidate will be discarded.
904              
905             If there are still multiple possible candidates, they will be sorted based
906             on how constrained they are.
907              
908             To determine how constrained they are, every type constraint in their
909             signature is assigned a score. B<Any> is 0. B<Defined> inherits from
910             B<Any>, so has score 1. B<Value> inherits from B<Defined>, so has score 2.
911             Etc. Some types inherit from a parent but without further constraining
912             the parent. (For example, B<Item> inherits from B<Any> but doesn't place
913             any additional constraints on values.) In these cases, the child type
914             has the same score as its parent. All these scores are added together
915             to get a single score for the candidate. For candidates where the
916             signature is a coderef, this is essentially a zero score for the
917             signature unless a score was specified explicitly.
918              
919             If multiple candidates are equally constrained, child class candidates
920             beat parent class candidates; class candidates beat role candidates;
921             and the candidate that was declared earlier wins.
922              
923             Method-resolution order (DFS/C3) is respected, though in Perl 5.8 under
924             very contrived conditions (calling a sub as a function when it was
925             defined as a method, but not passing a valid invocant as the first
926             parameter), MRO may not always work correctly.
927              
928             Note that invocants are not part of the signature, so not taken into
929             account when calculating scores, but because child class candidates
930             beat parent class candidates, they should mostly behave as expected.
931              
932             After this, there should be one preferred candidate or none. If there is
933             none, an error occurs. If there is one, that candidate is dispatched to
934             using C<goto> so there is no trace of Sub::MultiMethod in C<caller>. It
935             gets passed the result from checking the signature earlier as C<< @_ >>.
936              
937             =head3 Roles
938              
939             As far as I'm aware, Sub::MultiMethod is the only multimethod implementation
940             that allows multimethods imported from roles to integrate into a class.
941              
942             use v5.12;
943             use strict;
944             use warnings;
945            
946             package My::RoleA {
947             use Moo::Role;
948             use Sub::MultiMethod qw(multimethod);
949             use Types::Standard -types;
950            
951             multimethod foo => (
952             signature => [ HashRef ],
953             code => sub { return "A" },
954             alias => "foo_a",
955             );
956             }
957            
958             package My::RoleB {
959             use Moo::Role;
960             use Sub::MultiMethod qw(multimethod);
961             use Types::Standard -types;
962            
963             multimethod foo => (
964             signature => [ ArrayRef ],
965             code => sub { return "B" },
966             );
967             }
968            
969             package My::Class {
970             use Moo;
971             use Sub::MultiMethod qw(multimethod);
972             use Types::Standard -types;
973            
974             with qw( My::RoleA My::RoleB );
975            
976             multimethod foo => (
977             signature => [ HashRef ],
978             code => sub { return "C" },
979             );
980             }
981            
982             my $obj = My::Class->new;
983            
984             say $obj->foo_a( {} ); # A (alias defined in RoleA)
985             say $obj->foo( [] ); # B (candidate from RoleB)
986             say $obj->foo( {} ); # C (Class overrides candidate from RoleA)
987              
988             All other things being equal, candidates defined in classes should
989             beat candidates imported from roles.
990              
991             =head2 CodeRef multimethods
992              
993             The C<< $name >> of a multimethod may be a scalarref, in which case
994             C<multimethod> will install the multimethod as a coderef into the
995             scalar referred to. Example:
996              
997             my ($coderef, $otherref);
998            
999             multimethod \$coderef => (
1000             method => 0,
1001             signature => [ ArrayRef ],
1002             code => sub { say "It's an arrayref!" },
1003             );
1004            
1005             multimethod \$coderef => (
1006             method => 0,
1007             alias => \$otherref,
1008             signature => [ HashRef ],
1009             code => sub { say "It's a hashref!" },
1010             );
1011            
1012             $coderef->( [] );
1013             $coderef->( {} );
1014            
1015             $otherref->( {} );
1016              
1017             The C<< $coderef >> and C<< $otherref >> variables will actually end up
1018             as blessed coderefs so that some tidy ups can take place in C<DESTROY>.
1019              
1020             =head2 API
1021              
1022             Sub::MultiMethod avoids cute syntax hacks because those can be added by
1023             third party modules. It provides an API for these modules.
1024              
1025             Brief note on terminology: when you define multimethods in a class,
1026             each possible signature+coderef is a "candidate". The method which
1027             makes the decision about which candidate to call is the "dispatcher".
1028             Roles will typically have candidates but no dispatcher. Classes will
1029             need dispatchers setting up for each multimethod.
1030              
1031             =over
1032              
1033             =item C<< Sub::MultiMethod->install_candidate($target, $sub_name, %spec) >>
1034              
1035             C<< $target >> is the class (package) name being installed into.
1036              
1037             C<< $sub_name >> is the name of the method.
1038              
1039             C<< %spec >> is the multimethod spec. If C<< $target >> is a role, you
1040             probably want to include C<< no_dispatcher => 1 >> as part of the spec.
1041              
1042             =item C<< Sub::MultiMethod->install_dispatcher($target, $sub_name, $is_method) >>
1043              
1044             C<< $target >> is the class (package) name being installed into.
1045              
1046             C<< $sub_name >> is the name of the method.
1047              
1048             C<< $is_method >> is an integer/boolean.
1049              
1050             This rarely needs to be manually called as C<install_candidate> will do it
1051             automatically.
1052              
1053             =item C<< Sub::MultiMethod->install_monomethod($target, $sub_name, %spec) >>
1054              
1055             Installs a regular (non-multimethod) method into the target.
1056              
1057             =item C<< Sub::MultiMethod->copy_package_candidates(@sources => $target) >>
1058              
1059             C<< @sources >> is the list of packages to copy candidates from.
1060              
1061             C<< $target >> is the class (package) name being installed into.
1062              
1063             Sub::MultiMethod will use L<Role::Hooks> to automatically copy candidates
1064             from roles to consuming classes if your role implementation is supported.
1065             (Supported implementations include Role::Tiny, Role::Basic, Moo::Role,
1066             Moose::Role, and Mouse::Role, plus any role implementations that extend
1067             those. If your role implementation is something else, then when you consume
1068             a role into a class you may need to copy the candidates from the role to
1069             the class.)
1070              
1071             =item C<< Sub::MultiMethod->install_missing_dispatchers($target) >>
1072              
1073             Should usually be called after C<copy_package_candidates>, unless
1074             C<< $target >> is a role.
1075              
1076             Again, this is unnecessary if your role implementation is supported
1077             by Role::Hooks.
1078              
1079             =item C<< Sub::MultiMethod->get_multimethods($target) >>
1080              
1081             Returns the names of all multimethods declared for a class or role,
1082             not including any parent classes.
1083              
1084             =item C<< Sub::MultiMethod->has_multimethod_candidates($target, $method_name) >>
1085              
1086             Indicates whether the class or role has any candidates for a multimethod.
1087             Does not include parent classes.
1088              
1089             =item C<< Sub::MultiMethod->get_multimethod_candidates($target, $method_name) >>
1090              
1091             Returns a list of candidate spec hashrefs for the method, not including
1092             candidates from parent classes.
1093              
1094             =item C<< Sub::MultiMethod->get_all_multimethod_candidates($target, $method_name, $is_method) >>
1095              
1096             Returns a list of candidate spec hashrefs for the method, including candidates
1097             from parent classes (unless C<< $is_method >> is false, because non-methods
1098             shouldn't be inherited).
1099              
1100             =item C<< Sub::MultiMethod->known_dispatcher($coderef) >>
1101              
1102             Returns a boolean indicating whether the coderef is known to be a multimethod
1103             dispatcher.
1104              
1105             =item C<< Sub::MultiMethod->pick_candidate(\@candidates, \@args, \@invocants) >>
1106              
1107             Returns a list of three items: first the winning candidate from an array of specs,
1108             given the args and invocants, second the modified args after coercion has been
1109             applied, and third the modified invocants.
1110              
1111             This is basically how the dispatcher for a method works:
1112              
1113             my @invocants = splice(@_, 0, $ismethod);
1114             my $pkg = __PACKAGE__;
1115            
1116             my $smm = 'Sub::MultiMethod';
1117             my @candidates =
1118             $smm->get_all_multimethod_candidates($pkg, $sub, $ismethod);
1119             my ($winner, $new_args, $new_invocants) =
1120             $smm->pick_candidate(\@candidates, \@_, \@invocants);
1121            
1122             my $coderef = $winner->{code};
1123             @_ = (@$new_invocants, @$new_args);
1124             goto $coderef;
1125              
1126             =back
1127              
1128             =head1 BUGS
1129              
1130             Please report any bugs to
1131             L<http://rt.cpan.org/Dist/Display.html?Queue=Sub-MultiMethod>.
1132              
1133             =head1 SEE ALSO
1134              
1135             L<Class::Multimethods> - uses Perl classes and ref types to dispatch.
1136             No syntax hacks but the fairly nice syntax shown in the pod relies on
1137             C<use strict> being switched off! Need to quote a few more things otherwise.
1138              
1139             L<Class::Multimethods::Pure> - similar to Class::Multimethods but with
1140             a more complex type system and a more complex dispatch method.
1141              
1142             L<Logic> - a full declarative programming framework. Overkill if all
1143             you want is multimethods. Uses source filters.
1144              
1145             L<Dios> - object oriented programming framework including multimethods.
1146             Includes a full type system and Keyword::Declare-based syntax. Pretty
1147             sensible dispatch technique which is almost identical to
1148             Sub::MultiMethod. Much much slower though, at both compile time and
1149             runtime.
1150              
1151             L<MooseX::MultiMethods> - uses Moose type system and Devel::Declare-based
1152             syntax. Not entirely sure what the dispatching method is.
1153              
1154             L<Kavorka> - I wrote this, so I'm allowed to be critical. Type::Tiny-based
1155             type system. Very naive dispatching; just dispatches to the first declared
1156             candidate that can handle it rather than trying to find the "best". It is
1157             fast though.
1158              
1159             L<Sub::Multi::Tiny> - uses Perl attributes to declare candidates to
1160             be dispatched to. Pluggable dispatching, but by default uses argument
1161             count.
1162              
1163             L<Sub::Multi> - syntax wrapper around Class::Multimethods::Pure?
1164              
1165             L<Sub::SmartMatch> - kind of abandoned and smartmatch is generally seen
1166             as teh evilz these days.
1167              
1168             =head1 AUTHOR
1169              
1170             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
1171              
1172             =head1 COPYRIGHT AND LICENCE
1173              
1174             This software is copyright (c) 2020 by Toby Inkster.
1175              
1176             This is free software; you can redistribute it and/or modify it under
1177             the same terms as the Perl 5 programming language system itself.
1178              
1179             =head1 DISCLAIMER OF WARRANTIES
1180              
1181             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
1182             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1183             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1184