File Coverage

blib/lib/Future/AsyncAwait.pm
Criterion Covered Total %
statement 26 30 86.6
branch 3 6 50.0
condition n/a
subroutine 10 10 100.0
pod 0 3 0.0
total 39 49 79.5


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, 2016-2024 -- leonerd@leonerd.org.uk
5              
6             package Future::AsyncAwait 0.71;
7              
8 48     48   11449308 use v5.14;
  48         221  
9 48     48   301 use warnings;
  48         111  
  48         2817  
10              
11 48     48   312 use Carp;
  48         84  
  48         35343  
12              
13             require XSLoader;
14             XSLoader::load( __PACKAGE__, our $VERSION );
15              
16             require Future; Future->VERSION( '0.49' );
17              
18             =head1 NAME
19              
20             C - deferred subroutine syntax for futures
21              
22             =head1 SYNOPSIS
23              
24             =for highlighter language=perl
25              
26             use v5.14;
27             use Future::AsyncAwait;
28              
29             async sub do_a_thing
30             {
31             my $first = await do_first_thing();
32              
33             my $second = await do_second_thing();
34              
35             return combine_things( $first, $second );
36             }
37              
38             do_a_thing()->get;
39              
40             =head1 DESCRIPTION
41              
42             This module provides syntax for deferring and resuming subroutines while
43             waiting for Ls to complete. This syntax aims to make code that
44             performs asynchronous operations using futures look neater and more expressive
45             than simply using C chaining and other techniques on the futures
46             themselves. It is also a similar syntax used by a number of other languages;
47             notably C# 5, EcmaScript 6, Python 3, Dart, Rust, C++20.
48              
49             This module is still under active development. While it now seems relatively
50             stable enough for most use-cases and has received a lot of "battle-testing" in
51             a wide variety of scenarios, there may still be the occasional case of memory
52             leak left in it, especially if still-pending futures are abandoned.
53              
54             The new syntax takes the form of two new keywords, C and C.
55              
56             =head2 C
57              
58             The C keyword should appear just before the C keyword that
59             declares a new function. When present, this marks that the function performs
60             its work in a I asynchronous fashion. This has two effects: it
61             permits the body of the function to use the C expression, and it wraps
62             the return value of the function in a L instance.
63              
64             async sub myfunc
65             {
66             return 123;
67             }
68              
69             my $f = myfunc();
70             my $result = $f->get;
71              
72             As well as named function declarations it is also supported on anonymous
73             function expressions.
74              
75             my $code = async sub { return 456 };
76             my $f = $code->();
77             my $result = $f->get;
78              
79             This C-declared function always returns a C instance when
80             invoked. The returned future instance will eventually complete when the
81             function returns, either by the C keyword or by falling off the end;
82             the result of the future will be the return value from the function's code.
83             Alternatively, if the function body throws an exception, this will cause the
84             returned future to fail.
85              
86             If the final expression in the body of the function returns a C, don't
87             forget to C it rather than simply returning it as it is, or else this
88             return value will become double-wrapped - almost certainly not what you
89             wanted.
90              
91             async sub otherfunc { ... }
92              
93             async sub myfunc
94             {
95             ...
96             return await otherfunc();
97             }
98              
99             I this module also supports the C keyword on
100             lexical subroutine declarations when running on Perl version 5.18 or later.
101             Note that the C keyword has to come first:
102              
103             use v5.18;
104              
105             my async sub lexfunc { ... }
106              
107             my $f = lexfunc(@args);
108              
109             I this module supports using the C keyword to
110             declare named subs in other packages.
111              
112             async sub Some::Other::Package::myfunc { ... }
113              
114             =head2 C
115              
116             The C keyword forms an expression which takes a C instance as
117             an operand and yields the eventual result of it. Superficially it can be
118             thought of similar to invoking the C method on the future.
119              
120             my $result = await $f;
121              
122             my $result = $f->get;
123              
124             However, the key difference (and indeed the entire reason for being a new
125             syntax keyword) is the behaviour when the future is still pending and is not
126             yet complete. Whereas the simple C method would block until the future is
127             complete, the C keyword causes its entire containing function to become
128             suspended, making it return a new (pending) future instance. It waits in this
129             state until the future it was waiting on completes, at which point it wakes up
130             and resumes execution from the point of the C expression. When the
131             now-resumed function eventually finishes (either by returning a value or
132             throwing an exception), this value is set as the result of the future it had
133             returned earlier.
134              
135             C provides scalar context to its controlling expression.
136              
137             async sub func {
138             # this function is invoked in scalar context
139             }
140              
141             await func();
142              
143             Because the C keyword may cause its containing function to suspend
144             early, returning a pending future instance, it is only allowed inside
145             C-marked subs.
146              
147             The converse is not true; just because a function is marked as C does
148             not require it to make use of the C expression. It is still useful to
149             turn the result of that function into a future, entirely without Cing
150             on any itself.
151              
152             Any function that doesn't actually await anything, and just returns immediate
153             futures can be neatened by this module too.
154              
155             Instead of writing
156              
157             sub imm
158             {
159             ...
160             return Future->done( @result );
161             }
162              
163             you can now simply write
164              
165             async sub imm
166             {
167             ...
168             return @result;
169             }
170              
171             with the added side-benefit that any exceptions thrown by the elided code will
172             be turned into an immediate-failed C rather than making the call
173             itself propagate the exception, which is usually what you wanted when dealing
174             with futures.
175              
176             =head2 await (toplevel)
177              
178             I
179              
180             An C expression is also permitted directly in the main script at
181             toplevel, outside of C. This is implemented by simply invoking the
182             C method on the future value. Thus, the following two lines are directly
183             equivalent:
184              
185             await afunc();
186             afunc()->get;
187              
188             This is provided as a syntax convenience for unit tests, toplevel scripts, and
189             so on. It allows code to be written in a style that can be easily moved into
190             an C, and avoids encouraging "bad habits" of invoking the C
191             method directly.
192              
193             =head2 C
194              
195             I
196              
197             The C keyword declares a block of code which will be run in the event
198             that the future returned by the C is cancelled.
199              
200             async sub f
201             {
202             CANCEL { warn "This task was cancelled"; }
203              
204             await ...
205             }
206              
207             f()->cancel;
208              
209             A C block is a self-contained syntax element, similar to perl
210             constructions like C, and does not need a terminating semicolon.
211              
212             When a C block is encountered during execution of the C,
213             the code in its block is stored for the case that the returned future is
214             cancelled. Each will take effect as it is executed, possibly multiple times if
215             it appears inside a loop, or not at all if it appears conditionally in a
216             branch that was not executed.
217              
218             async sub g
219             {
220             if(0) {
221             CANCEL { warn "This does not happen"; }
222             }
223              
224             foreach my $x ( 1..3 ) {
225             CANCEL { warn "This happens for x=$x"; }
226             }
227              
228             await ...
229             }
230              
231             g()->cancel;
232              
233             C blocks are only invoked if a still-pending future is cancelled. They
234             are discarded without being executed if the function finishes; either
235             successfully or if it throws an exception.
236              
237             =head1 Experimental Features
238              
239             Some of the features of this module are currently marked as experimental. They
240             will provoke warnings in the C category, unless silenced.
241              
242             You can silence this with C but then that will
243             silence every experimental warning, which may hide others unintentionally. For
244             a more fine-grained approach you can instead use the import line for this
245             module to only silence this module's warnings selectively:
246              
247             use Future::AsyncAwait qw( :experimental(cancel) );
248              
249             use Future::AsyncAwait qw( :experimental ); # all of the above
250              
251             =head1 SUPPORTED USES
252              
253             Most cases involving awaiting on still-pending futures should work fine:
254              
255             async sub foo
256             {
257             my ( $f ) = @_;
258              
259             BEFORE();
260             await $f;
261             AFTER();
262             }
263              
264             async sub bar
265             {
266             my ( $f ) = @_;
267              
268             return 1 + await( $f ) + 3;
269             }
270              
271             async sub splot
272             {
273             while( COND ) {
274             await func();
275             }
276             }
277              
278             async sub wibble
279             {
280             if( COND ) {
281             await func();
282             }
283             }
284              
285             async sub wobble
286             {
287             foreach my $var ( THINGs ) {
288             await func();
289             }
290             }
291              
292             async sub wubble
293             {
294             # on perl 5.35.5 and above
295             foreach my ($k, $v) ( KVTHINGs ) {
296             await func();
297             }
298             }
299              
300             async sub quux
301             {
302             my $x = do {
303             await func();
304             };
305             }
306              
307             async sub splat
308             {
309             eval {
310             await func();
311             };
312             }
313              
314             Plain lexical variables are preserved across an C deferral:
315              
316             async sub quux
317             {
318             my $message = "Hello, world\n";
319             await func();
320             print $message;
321             }
322              
323             On perl versions 5.26 and later C syntax supports the C
324             feature if it is enabled:
325              
326             use v5.26;
327             use feature 'signatures';
328              
329             async sub quart($x, $y)
330             {
331             ...
332             }
333              
334             I any exceptions thrown by signature validation (because
335             of too few or too many arguments being passed) are thrown synchronously, and
336             do not result in a failed Future instance.
337              
338             =head2 Cancellation
339              
340             Cancelled futures cause a suspended C to simply stop running.
341              
342             async sub fizz
343             {
344             await func();
345             say "This is never reached";
346             }
347              
348             my $f = fizz();
349             $f->cancel;
350              
351             Cancellation requests can propagate backwards into the future the
352             C is currently waiting on.
353              
354             async sub floof
355             {
356             ...
357             await $f1;
358             }
359              
360             my $f2 = floof();
361              
362             $f2->cancel; # $f1 will be cancelled too
363              
364             This behaviour is still more experimental than the rest of the logic. The
365             following should be noted:
366              
367             =over 4
368              
369             =item *
370              
371             Cancellation propagation is only implemented on Perl version 5.24 and above.
372             An C in an earlier perl version will still stop executing if
373             cancelled, but will not propagate the request backwards into the future that
374             the C is currently waiting on. See L.
375              
376             =back
377              
378             =head1 SUBCLASSING Future
379              
380             By default when an C returns a result or fails immediately before
381             awaiting, it will return a new completed instance of the L class. In
382             order to allow code that wishes to use a different class to represent futures
383             the module import method can be passed the name of a class to use instead.
384              
385             use Future::AsyncAwait future_class => "Subclass::Of::Future";
386              
387             async sub func { ... }
388              
389             This has the usual lexically-scoped effect, applying only to Cs
390             defined within the block; others are unaffected.
391              
392             use Future::AsyncAwait;
393              
394             {
395             use Future::AsyncAwait future_class => "Different::Future";
396             async sub x { ... }
397             }
398              
399             async sub y { ... } # returns a regular Future
400              
401             This will only affect immediate results. If the C keyword has to
402             suspend the function and create a new pending future, it will do this by using
403             the prototype constructor on the future it itself is waiting on, and the usual
404             subclass-respecting semantics of L will remain in effect there. As
405             such it is not usually necessary to use this feature just for wrapping event
406             system modules or other similar situations.
407              
408             Such an alternative subclass should implement the API documented by
409             L.
410              
411             =head1 WITH OTHER MODULES
412              
413             =head2 Syntax::Keyword::Try
414              
415             As of L version 0.10 and L version
416             0.07, cross-module integration tests assert that basic C blocks
417             inside an C work correctly, including those that attempt to
418             C from inside C.
419              
420             use Future::AsyncAwait;
421             use Syntax::Keyword::Try;
422              
423             async sub attempt
424             {
425             try {
426             await func();
427             return "success";
428             }
429             catch {
430             return "failed";
431             }
432             }
433              
434             As of L version 0.50, C blocks are invoked even
435             during cancellation.
436              
437             =head2 Syntax::Keyword::Dynamically
438              
439             As of L version 0.32, cross-module integration tests
440             assert that the C correctly works across an C boundary.
441              
442             use Future::AsyncAwait;
443             use Syntax::Keyword::Dynamically;
444              
445             our $var;
446              
447             async sub trial
448             {
449             dynamically $var = "value";
450              
451             await func();
452              
453             say "Var is still $var";
454             }
455              
456             =head2 Syntax::Keyword::Defer
457              
458             As of L version 0.50, C blocks are invoked even
459             during cancellation.
460              
461             use Future::AsyncAwait;
462             use Syntax::Keyword::Defer;
463              
464             async sub perhaps
465             {
466             defer { say "Cleaning up now" }
467             await $f1;
468             }
469              
470             my $fouter = perhaps();
471             $fouter->cancel;
472              
473             =head2 Object::Pad
474              
475             As of L version 0.38 and L version 0.15, both
476             modules now use L to parse blocks of code. Because of this
477             the two modules can operate together and allow class methods to be written as
478             async subs which await expressions:
479              
480             use Future::AsyncAwait;
481             use Object::Pad;
482              
483             class Example
484             {
485             async method perform($block)
486             {
487             say "$self is performing code";
488             await $block->();
489             say "code finished";
490             }
491             }
492              
493             =head2 Syntax::Keyword::MultiSub
494              
495             As of L version 0.55 and L
496             version 0.02 a cross-module integration test asserts that the C
497             modifier can be applied to C.
498              
499             use Future::AsyncAwait;
500             use Syntax::Keyword::MultiSub;
501              
502             async multi sub f () { return "nothing"; }
503             async multi sub f ($key) { return await get_thing($key); }
504              
505             =cut
506              
507             sub import
508             {
509 45     45   358761 my $pkg = shift;
510 45         122 my $caller = caller;
511              
512 45         181 $pkg->import_into( $caller, @_ );
513             }
514              
515             sub unimport
516             {
517 1     1   9 my $pkg = shift;
518 1         2 my $caller = caller;
519              
520 1         3 $pkg->unimport_into( $caller, @_ );
521             }
522              
523 46     46 0 2365 sub import_into { shift->apply( sub { $^H{ $_[0] }++ }, @_ ) }
  45     45   303  
524 1     1 0 5 sub unimport_into { shift->apply( sub { delete $^H{ $_[0] } }, @_ ) }
  1     1   5  
525              
526             my @EXPERIMENTAL = qw( cancel );
527              
528             sub apply
529             {
530 46     46 0 145 my $pkg = shift;
531 46         152 my ( $cb, $caller, @syms ) = @_;
532              
533 46         198 $cb->( "Future::AsyncAwait/async" ); # Just always turn this on
534              
535 46         81755 SYM: while( @syms ) {
536 2         4 my $sym = shift @syms;
537              
538 2 100       110 $^H{"Future::AsyncAwait/future"} = shift @syms, next if $sym eq "future_class";
539              
540 1         2 foreach ( @EXPERIMENTAL ) {
541 1 50       3 $cb->( "Future::AsyncAwait/experimental($_)" ), next SYM if $sym eq ":experimental($_)";
542             }
543 0 0         if( $sym eq ":experimental" ) {
544 0           $cb->( "Future::AsyncAwait/experimental($_)" ) for @EXPERIMENTAL;
545 0           next SYM;
546             }
547              
548 0           croak "Unrecognised import symbol $sym";
549             }
550             }
551              
552             =head1 SEE ALSO
553              
554             =over 4
555              
556             =item *
557              
558             "Awaiting The Future" - TPC in Amsterdam 2017
559              
560             L L<(slides)|https://docs.google.com/presentation/d/13x5l8Rohv_RjWJ0OTvbsWMXKoNEWREZ4GfKHVykqUvc/edit#slide=id.p>
561              
562             =back
563              
564             =head1 TODO
565              
566             =over 4
567              
568             =item *
569              
570             Suspend and resume with some consideration for the savestack; i.e. the area
571             used to implement C and similar. While in general C support has
572             awkward questions about semantics, there are certain situations and cases
573             where internally-implied localisation of variables would still be useful and
574             can be supported without the semantic ambiguities of generic C.
575              
576             our $DEBUG = 0;
577              
578             async sub quark
579             {
580             local $DEBUG = 1;
581             await func();
582             }
583              
584             Since C loops on non-lexical iterator variables (usually the C<$_>
585             global variable) effectively imply a C-like behaviour, these are also
586             disallowed.
587              
588             async sub splurt
589             {
590             foreach ( LIST ) {
591             await ...
592             }
593             }
594              
595             Some notes on what makes the problem hard can be found at
596              
597             L
598              
599             =item *
600              
601             Currently this module requires perl version 5.16 or later. Additionally,
602             threaded builds of perl earlier than 5.22 are not supported.
603              
604             L
605              
606             L
607              
608             =item *
609              
610             Implement cancel back-propagation for Perl versions earlier than 5.24.
611             Currently this does not work due to some as-yet-unknown effects that
612             installing the back-propagation has, causing future instances to be reclaimed
613             too early.
614              
615             L
616              
617             =back
618              
619             =head1 KNOWN BUGS
620              
621             This is not a complete list of all known issues, but rather a summary of the
622             most notable ones that currently prevent the module from working correctly in
623             a variety of situations. For a complete list of known bugs, see the RT queue
624             at L.
625              
626             =over 4
627              
628             =item *
629              
630             C inside C or C blocks does not work. This is due to the
631             difficulty of detecting the map or grep context from internal perl state at
632             suspend time, sufficient to be able to restore it again when resuming.
633              
634             L
635              
636             As a workaround, consider converting a C expression to the equivalent
637             form using C onto an accumulator array with a C loop:
638              
639             my @results = map { await func($_) } ITEMS;
640              
641             becomes
642              
643             my @results;
644             foreach my $item ( ITEMS ) {
645             push @results, await func($item);
646             }
647              
648             with a similar transformation for C expressions.
649              
650             Alternatively, consider using the C family of functions from
651             L to provide a concurrent version of the same code, which can
652             keep multiple items running concurrently:
653              
654             use Future::Utils qw( fmap );
655              
656             my @results = await fmap { func( shift ) }
657             foreach => [ ITEMS ],
658             concurrent => 5;
659              
660             =item *
661              
662             The default arguments array (C<@_>) is not saved and restored by an C
663             call on perl versions before v5.24. On such older perls, the value seen in the
664             C<@_> array after an await will not be the same as it was before.
665              
666             L
667              
668             As a workaround, make sure to unpack the values out of it into regular lexical
669             variables early on, before the the first C. The values of these
670             lexicals will be saved and restored as normal.
671              
672             async sub f
673             {
674             my ($vars, $go, @here) = @_;
675             # do not make further use of @_ afterwards
676              
677             await thing();
678              
679             # $vars, $go, @here are all fine for use
680             }
681              
682             =back
683              
684             =cut
685              
686             =head1 ACKNOWLEDGEMENTS
687              
688             With thanks to C, C and others from C for
689             assisting with trickier bits of XS logic.
690              
691             Thanks to C for project management and actually reminding me to write
692             some code.
693              
694             Thanks to The Perl Foundation for sponsoring me to continue working on the
695             implementation.
696              
697             =head1 AUTHOR
698              
699             Paul Evans
700              
701             =cut
702              
703             0x55AA;