File Coverage

blib/lib/Syntax/Keyword/MultiSub.pm
Criterion Covered Total %
statement 23 25 92.0
branch 1 2 50.0
condition n/a
subroutine 10 10 100.0
pod 0 3 0.0
total 34 40 85.0


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2021-2023 -- leonerd@leonerd.org.uk
5              
6             package Syntax::Keyword::MultiSub 0.04;
7              
8 2     2   238893 use v5.14;
  2         14  
9 2     2   11 use warnings;
  2         4  
  2         60  
10              
11 2     2   10 use Carp;
  2         4  
  2         741  
12              
13             require XSLoader;
14             XSLoader::load( __PACKAGE__, our $VERSION );
15              
16             =encoding UTF-8
17              
18             =head1 NAME
19              
20             C - multiple dispatch on subroutines
21              
22             =head1 SYNOPSIS
23              
24             use v5.26;
25             use Syntax::Keyword::MultiSub;
26             use experimental 'signatures';
27              
28             multi sub max() { return undef; }
29             multi sub max($x) { return $x; }
30             multi sub max($x, @more) { my $y = max(@more);
31             return $x > $y ? $x : $y; }
32              
33             say max(1, 2, 15, 3, 4); # prints 15
34              
35             =head1 DESCRIPTION
36              
37             This module provides a new keyword, C, to put before subroutine
38             declarations, which permits multiple distinct function bodies to be provided,
39             which take different parameters. A call to a C will invoke
40             whichever function body best fits the arguments passed.
41              
42             Currently this module can only make dispatching decisions based on the number
43             of arguments as compared to the number of signature parameters each body was
44             expecting. It requires F version 5.26 or above, in order to get enough
45             support from signatures. Note also enabling this module does not enable the
46             C feature; you must do that independently.
47              
48             =cut
49              
50             =head1 KEYWORDS
51              
52             =head2 multi
53              
54             multi sub NAME (SIGNATURE) { BODY... }
55              
56             Declares an alternative for the C of the given name. Each
57             alternative will be distinguished by the number of parameters its signature
58             declares. If the signature includes optional parameters, this alternative is
59             considered to cover the entire range from none to all of the optional ones
60             being present. The ranges of parameter count covered by every alternative to
61             a given function name must be non-overlapping; it is a compiletime error for
62             two function bodies to claim the same number of parameters.
63              
64             Each of the non-final alternatives for any given name must use only scalar
65             parameters (though some may be optional); but as a special-case, the final
66             alternative may end in a slurpy parameter (either an array or a hash). If this
67             is the case then it will be considered for dispatch if none of the previous
68             alternatives match, as long as it has at least the minimum number of required
69             parameters present.
70              
71             =cut
72              
73             sub import
74             {
75 1     1   8 my $pkg = shift;
76 1         2 my $caller = caller;
77              
78 1         4 $pkg->import_into( $caller, @_ );
79             }
80              
81             sub unimport
82             {
83 1     1   10 my $pkg = shift;
84 1         3 my $caller = caller;
85              
86 1         3 $pkg->unimport_into( $caller, @_ );
87             }
88              
89 1     1 0 8 sub import_into { shift->apply( sub { $^H{ $_[0] }++ }, @_ ) }
  1     1   5  
90 1     1 0 5 sub unimport_into { shift->apply( sub { delete $^H{ $_[0] } }, @_ ) }
  1     1   6  
91              
92             sub apply
93             {
94 2     2 0 3 my $pkg = shift;
95 2         6 my ( $cb, $caller, @syms ) = @_;
96              
97 2         4 my %syms = map { $_ => 1 } @syms;
  0         0  
98 2         6 $cb->( "Syntax::Keyword::MultiSub/multi" );
99              
100 2 50       2834 croak "Unrecognised import symbols @{[ keys %syms ]}" if keys %syms;
  0            
101             }
102              
103             =head1 WITH OTHER MODULES
104              
105             =head2 Future::AsyncAwait
106              
107             As of L version 0.55 a cross-module integration test
108             asserts that the C modifier can be applied to C.
109              
110             use Future::AsyncAwait;
111             use Syntax::Keyword::MultiSub;
112              
113             async multi sub f () { return "nothing"; }
114             async multi sub f ($key) { return await get_thing($key); }
115              
116             =head1 TODO
117              
118             =over 4
119              
120             =item *
121              
122             Much better error checking and diagnostics for function bodies that don't use
123             signatures.
124              
125             =item *
126              
127             Cross-module testing with L (for C). This may
128             require a better combined implementation, to be aware of method resolution
129             order, inheritence, etc...
130              
131             =item *
132              
133             An eventual consideration of type assertions or value testing, as well as
134             simple argument count.
135              
136             This particular task is likely to be a large undertaking as it spans several
137             other areas of language. As well as types on parameters, it would be nice to
138             put them on lexical variables, object slots, C comparisons, and so
139             on. It would be a shame to invent a special mechanism for one of these areas
140             that could not be reĆ¼sed by the others.
141              
142             =back
143              
144             =cut
145              
146             =head1 AUTHOR
147              
148             Paul Evans
149              
150             =cut
151              
152             0x55AA;