File Coverage

blib/lib/Syntax/Keyword/MultiSub.pm
Criterion Covered Total %
statement 16 18 88.8
branch 1 2 50.0
condition n/a
subroutine 5 5 100.0
pod 0 1 0.0
total 22 26 84.6


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 -- leonerd@leonerd.org.uk
5              
6             package Syntax::Keyword::MultiSub 0.03;
7              
8 2     2   238633 use v5.14;
  2         16  
9 2     2   14 use warnings;
  2         4  
  2         49  
10              
11 2     2   10 use Carp;
  2         5  
  2         569  
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 $class = shift;
76 1         3 my $caller = caller;
77              
78 1         3 $class->import_into( $caller, @_ );
79             }
80              
81             sub import_into
82             {
83 1     1 0 2 my $class = shift;
84 1         2 my ( $caller, @syms ) = @_;
85              
86 1         2 my %syms = map { $_ => 1 } @syms;
  0         0  
87 1         6 $^H{"Syntax::Keyword::MultiSub/multi"}++;
88              
89 1 50       2744 croak "Unrecognised import symbols @{[ keys %syms ]}" if keys %syms;
  0            
90             }
91              
92             =head1 WITH OTHER MODULES
93              
94             =head2 Future::AsyncAwait
95              
96             As of L version 0.55 a cross-module integration test
97             asserts that the C modifier can be applied to C.
98              
99             use Future::AsyncAwait;
100             use Syntax::Keyword::MultiSub;
101              
102             async multi sub f () { return "nothing"; }
103             async multi sub f ($key) { return await get_thing($key); }
104              
105             =head1 TODO
106              
107             =over 4
108              
109             =item *
110              
111             Much better error checking and diagnostics for function bodies that don't use
112             signatures.
113              
114             =item *
115              
116             Cross-module testing with L (for C). This may
117             require a better combined implementation, to be aware of method resolution
118             order, inheritence, etc...
119              
120             =item *
121              
122             An eventual consideration of type assertions or value testing, as well as
123             simple argument count.
124              
125             This particular task is likely to be a large undertaking as it spans several
126             other areas of language. As well as types on parameters, it would be nice to
127             put them on lexical variables, object slots, C comparisons, and so
128             on. It would be a shame to invent a special mechanism for one of these areas
129             that could not be reĆ¼sed by the others.
130              
131             =back
132              
133             =cut
134              
135             =head1 AUTHOR
136              
137             Paul Evans
138              
139             =cut
140              
141             0x55AA;