@@ -259,15 +259,13 @@ which returns an element from the C<PromiseStatus> enumeration.
259
259
enum PromiseStatus (:Planned(0), :Kept(1), :Broken(2));
260
260
261
261
The result itself can be obtained by calling C<result>. If the C<Promise> was
262
- already kept, the result is immediately returned. If the C<Promise> was
263
- broken then the exception that it was broken with is thrown.
264
-
265
- If the C<Promise> is not yet kept or broken, then the caller will block until
266
- any of these status changes happen.
262
+ already kept, the result is immediately returned. If the C<Promise> was broken
263
+ then the exception that it was broken with is thrown. If the C<Promise> is not
264
+ yet kept or broken, then the caller will block until this happens.
267
265
268
266
A C<Promise> will boolify to whether the C<Promise> is already kept or broken.
269
- There is also an C<excuse> method for extracting the exception from a
270
- C<Broken> C< Promise> rather than having it thrown.
267
+ There is also an C<excuse> method for extracting the exception from a C<Broken>
268
+ C<Promise> rather than having it thrown.
271
269
272
270
if $promise {
273
271
if $promise.status == Kept {
@@ -284,9 +282,9 @@ C<Broken> C<Promise> rather than having it thrown.
284
282
You can also simply use a switch:
285
283
286
284
given $promise.status {
287
- when Planned { say "Still working!" }
288
- when Kept { say "Kept, result = ", $promise.result }
289
- when Broken { say "Broken because ", $promise.excuse }
285
+ when Planned { say "Still working!" }
286
+ when Kept { say "Kept, result = ", $promise.result }
287
+ when Broken { say "Broken because ", $promise.excuse }
290
288
}
291
289
292
290
There are various convenient "factory" methods on C<Promise>. The most common
@@ -354,13 +352,13 @@ a promise is user-facing. To instead represent the promise from the
354
352
viewpoint of the promiser, the various built-in C<Promise> factory methods
355
353
and combinators use C<Promise::Vow> objects to represent that internal
356
354
resolve to fulfill the promise. ("I have vowed to keep my promise
357
- to you.") The C<vow> method on a C<Promise> returns an object with C<keep>,
358
- and C<break> methods. It can only be called once during a C<Promise>
359
- object's lifetime. Since C<keep> and C<break> on the C<Promise> itself just
360
- delegate to C<self.vow.keep(...)> or C<self.vow.break(...)>, obtaining the
361
- vow before letting the C<Promise> escape to the outside world is a way to
362
- take ownership of the right to keep or break it. For example, here is how
363
- the C<Promise.in> factory is implemented:
355
+ to you.") The C<vow> method on a C<Promise> returns an object with C<keep>
356
+ and C<break> methods. It can only be called once during a C<Promise> object's
357
+ lifetime. Since C<keep> and C<break> on the C<Promise> itself just delegate
358
+ to C<self.vow.keep(...)> or C<self.vow.break(...)>, obtaining the vow
359
+ before letting the C<Promise> escape to the outside world is a way to take
360
+ ownership of the right to keep or break it. For example, here is how the
361
+ C<Promise.in> factory is implemented:
364
362
365
363
method in(Promise:U: $seconds, :$scheduler = $*SCHEDULER) {
366
364
my $p = Promise.new(:$scheduler);
@@ -375,7 +373,45 @@ result.
375
373
my ($a, $b) = await $p1, $p2;
376
374
377
375
This simply calls C<result> on each of the C<Promise>s, so any exception will
378
- be thrown.
376
+ be thrown. There is also a C<winner> statement [keywords still negotiable]:
377
+
378
+ winner * {
379
+ done $p1 { say "First promise got a value" }
380
+ done $p2 { say "Second promise got a value" }
381
+ }
382
+
383
+ That will invoke the closure associated with the first promise that
384
+ produces a result, either kept or broken.
385
+
386
+ It's possible to add a timer using the keyword C<wait> followed
387
+ by the number of seconds to wait (which may be fractional). As a
388
+ degenerate case, in order to avoid blocking at all you may use a
389
+ C<wait 0>. The timeout is always checked last, to guarantee that
390
+ the other entries are all tried at least once before timing out.
391
+
392
+ my $gotone = winner * {
393
+ done $p1 { say "First promise got a value"; $p1 }
394
+ done $p2 { say "Second promise got a value"; $p2 }
395
+ wait 0 { say "Not done yet"; Nil }
396
+ }
397
+
398
+ The construct as a whole returns the result of whichever block was selected.
399
+
400
+ It's also possible to process a variadic list of promises together,
401
+ using generic code that works over some set of the promises (use C<*>
402
+ to represent any of them). The index and promise are passed to the
403
+ code as named arguments C<$:v> and <$:k> (possibly via priming if
404
+ the code is instantiated ahead of time).
405
+
406
+ winner * {
407
+ done @promises { say "Promise $:k was kept, result was: ", $:v.result }
408
+ }
409
+
410
+ In this case C<$:k> returns the index of the promise, base 0.
411
+ Likewise C<$:v> returns the promise object itself. Conjecture: the result
412
+ should be bound to C<$_> to make it work more like channels below.
413
+
414
+ [Conjecture: we should allow different cases for success or failure.]
379
415
380
416
=head1 Channels
381
417
@@ -411,6 +447,22 @@ calls to a channel return the same promise, not a new one.
411
447
While C<receive> blocks until it can read, C<poll> takes a message from the
412
448
channel if one is there or immediately returns C<Nil> if nothing is there.
413
449
450
+ The C<winner> construct also works on channels, and will try to receive a value
451
+ from the first C<Channel> that has one available. It also automatically checks
452
+ the C<.done> promise corresponding to the channel, so it can also be used in order
453
+ to write a loop to receive from a channel until it is closed:
454
+
455
+ gather loop {
456
+ winner $channel {
457
+ more * { take $_ }
458
+ done * { last }
459
+ }
460
+ }
461
+
462
+ This works because C<more> only ever works on channels, while C<done>
463
+ only ever works on promises, so it knows to check the promise of
464
+ channel C<$c> rather than C<$c> itself.
465
+
414
466
This is such a common pattern that we make a channel in list context behave
415
467
that way:
416
468
@@ -421,89 +473,6 @@ that way:
421
473
the reactive realm to the lazy realm. Some reasonable amount of buffering
422
474
is assumed between the two.)
423
475
424
- =head1 Outcome
425
-
426
- There is an C<outcome> statement [keywords still negotiable]. In its
427
- simplest form it just takes a list of C<Promise>s and / or C<Channel>s and
428
- returns a lazy list of all the values returned by all Promises and Channels
429
- specified:
430
-
431
- my @values = outcome @p, @c;
432
-
433
- If a C<Promise> is broken, then the value returned is a C<Failure> object
434
- with the C<.excuse>. Please note that this simple form will block until all
435
- values have been found. You can also put this simple form in a loop for
436
- processing:
437
-
438
- for outcome( @p, @c ) -> $value {
439
- # process $value
440
- }
441
-
442
- in which case values will be processed as they become available.
443
-
444
- For more control, one can also specify a closure, in which there is more
445
- control over how a C<Promise> and / or a C<Channel> are being processed.
446
- In such a case, the returned lazy list with values is generally not needed:
447
-
448
- my @values;
449
- outcome {
450
- whenever $p1 { say "p1 fired"; @values.push: $_ }
451
- whenever @p,@c { @values.push: $_ }
452
- }
453
-
454
- Please note that for C<Promise>s, the C<whenever> will only be called once.
455
- For C<Channel>s, it will be called as soon as a value is present on the
456
- Channel until the Channel is C<.closed>.
457
-
458
- There is also a C<done> keyword that can be used to specify code to be run
459
- when a C<Channel> has closed:
460
-
461
- outcome {
462
- ...
463
- done @c { say "Channel $_ has closed" }
464
- }
465
-
466
- It's possible to add a timer using the keyword C<wait> followed by the
467
- number of seconds to wait (which may be fractional) since the last value
468
- found by a C<whenever> has been seen. The timeout is always checked last,
469
- to guarantee that the other entries are all tried at least once before
470
- timing out.
471
-
472
- outcome {
473
- ...
474
- wait 5 { say "Not done yet" }
475
- }
476
-
477
- As a degenerate case, in order to avoid blocking at all you may use a
478
- C<wait 0>. Together with C<last>, this allows one to exit the C<outcome>
479
- prematurely whenever there is nothing happening:
480
-
481
- loop {
482
- outcome {
483
- ...
484
- wait 0 { say "Giving up for now"; last }
485
- }
486
- # do other stuff
487
- }
488
-
489
- Please note that you will to somehow make sure that C<Promise> that has been
490
- kept or broken, will not be seen again in the next loop iteration. Something
491
- like this:
492
-
493
- my @values;
494
- my @seen;
495
- loop {
496
- outcome {
497
- whenever @p {
498
- if !@seen.first: { $_ === $:promise } {
499
- @values.push: $_;
500
- @seen.push: $:promise;
501
- }
502
- wait 0 { say "Giving up for now"; last }
503
- }
504
- # do other stuff
505
- }
506
-
507
476
=head1 Supplies
508
477
509
478
Channels are good for producer/consumer scenarios, but because each worker
0 commit comments