<commit_before>=begin pod

=TITLE class Promise

=SUBTITLE Status/result of an asynchronous computation

    my enum PromiseStatus (:Planned(0), :Kept(1), :Broken(2));
    class Promise { ... }

A I<Promise> is used to handle the result of a computation that might not have
finished. It allows the user to execute code once the computation is done
(with the C<then> method), execution after a time delay (with C<in>),
combining promises, and waiting for results.

    my $p = Promise.start({ sleep 2; 42});
    $p.then({ say .result });   # will print 42 once the block finished
    say $p.status;              # Planned
    $p.result;                  # waits for the computation to finish
    say $p.status;              # Kept

There are two typical scenarios for using promises. The first is to use a
factory method (C<start>, C<in>, C<anyof>, C<allof>) on the type object; those
will make sure that the promise is automatically kept or broken for you, and
you can't call C<break> or C<keep> on these promises yourself.

The second is to create your promises yourself with C<Promise.new>. If you
want to ensure that only your code can keep or break the promise, you can use
the C<vow> method to get a unique handle, and call C<keep> or C<break> on it:

=begin code
    sub async-get-with-promise($user-agent, $url) {
        my $p = Promise.new;
        my $v = $p.vow;

        # do an asynchronous call on a fictive user agent,
        # and return the promise:
        $user-agent.async-get($url,
                on-error => -> $error {
                    $v.break($error);
                },
                on-success => -> $response {
                    $v.keep($response);
                }
        );
        return $p;
    }
=end code

=head1 Methods

=head2 method start

    sub start(&code);
    method start(Promise:U: &code, :$scheduler = $*SCHEDULER) returns Promise:D

Creates a new Promise that runs the given code object. The promise will be
kept when the code terminates normally, or broken if it throws an exception.
The return value or exception can be inspected with the C<result> method.

The scheduler that handles this promise can be passed as a named argument.

    # these two are equivalent:
    my $p1 = Promise.start({ do something here });
    my $p2 = start { do something here };

=head2 method in

    method in(Promise:U: $seconds, :$scheduler = $*SCHEDULER) returns Promise:D

Creates a new Promise that will be kept in C<$seconds> seconds, or later.

    my $p = Promise.in(5).then({ say "5 seconds later" });
    # do other stuff here

    await $p;   # wait here until the 5 seconds are over

=head2 method allof

    method allof(Promise:U: *@promises) returns Promise:D

Returns a new promise that will be kept when all the promises passed as
arguments are kept, and that will be broken as soon as any of the argument
promises is broken.

    my @promises;
    for 1..5 -> $t {
        push @promises, start {
            sleep $t;
            die "OH NOEZ" if rand < 0.2;
        };
    }
    my $all-successful = Promise.allof(@promises);
    await $all-successful;

=head2 method anyof

    method anyof(Promise:U: *@promises) returns Promise:D

Returns a new promise that will be kept as soon as any of the promises passed as
arguments is kept, and will be broken when all of the argument promises are
broken.

You can use this to wait at most a number of seconds for a promise:

    my $timeout = 5;
    await Promise.anyof(
        Promise.in($timeout),
        start {
            # do a potentially long-running calculation here
        },
    );

=head2 method then

    method then(Promise:D: &code)

Schedules a piece of code to be run after the invocant has been kept or<commit_msg>Extend example for clarity<commit_after>=begin pod

=TITLE class Promise

=SUBTITLE Status/result of an asynchronous computation

    my enum PromiseStatus (:Planned(0), :Kept(1), :Broken(2));
    class Promise { ... }

A I<Promise> is used to handle the result of a computation that might not have
finished. It allows the user to execute code once the computation is done
(with the C<then> method), execution after a time delay (with C<in>),
combining promises, and waiting for results.

    my $p = Promise.start({ sleep 2; 42});
    $p.then({ say .result });   # will print 42 once the block finished
    say $p.status;              # Planned
    $p.result;                  # waits for the computation to finish
    say $p.status;              # Kept

There are two typical scenarios for using promises. The first is to use a
factory method (C<start>, C<in>, C<anyof>, C<allof>) on the type object; those
will make sure that the promise is automatically kept or broken for you, and
you can't call C<break> or C<keep> on these promises yourself.

The second is to create your promises yourself with C<Promise.new>. If you
want to ensure that only your code can keep or break the promise, you can use
the C<vow> method to get a unique handle, and call C<keep> or C<break> on it:

=begin code
    sub async-get-with-promise($user-agent, $url) {
        my $p = Promise.new;
        my $v = $p.vow;

        # do an asynchronous call on a fictive user agent,
        # and return the promise:
        $user-agent.async-get($url,
                on-error => -> $error {
                    $v.break($error);
                },
                on-success => -> $response {
                    $v.keep($response);
                }
        );
        return $p;
    }
=end code

=head1 Methods

=head2 method start

    sub start(&code);
    method start(Promise:U: &code, :$scheduler = $*SCHEDULER) returns Promise:D

Creates a new Promise that runs the given code object. The promise will be
kept when the code terminates normally, or broken if it throws an exception.
The return value or exception can be inspected with the C<result> method.

The scheduler that handles this promise can be passed as a named argument.

    # these two are equivalent:
    my $p1 = Promise.start({ do something here });
    my $p2 = start { do something here };

=head2 method in

    method in(Promise:U: $seconds, :$scheduler = $*SCHEDULER) returns Promise:D

Creates a new Promise that will be kept in C<$seconds> seconds, or later.

    my $p = Promise.in(5).then({ say "5 seconds later" });
    # do other stuff here

    await $p;   # wait here until the 5 seconds are over

=head2 method allof

    method allof(Promise:U: *@promises) returns Promise:D

Returns a new promise that will be kept when all the promises passed as
arguments are kept, and that will be broken as soon as any of the argument
promises is broken. You may need to run the following code several times
before none of the promises get broken with C<die> and we get to
the C<say> on the last line, instead of bailing out on C<await>.

    my @promises;
    for 1..5 -> $t {
        push @promises, start {
            sleep $t;
            die "OH NOEZ" if rand < 0.2;
        };
    }
    my $all-successful = Promise.allof(@promises);
    await $all-successful;
    say "Promises kept so we get to live another day!";

=head2 method anyof

    method anyof(Promise:U: *@promises) returns Promise:D

Returns a new promise that will be kept as soon as any of the promises passed as
arguments is kept, and will be broken when all of the argument promises are
broken.

You can use this to wait at most a number of seconds for a promise:

    my $timeout = 5;
    await Promise.anyof(
        Promise.in($timeout),
        start {
            # do a potentially long-running calculation here
        },
    );

=head2 method then

    method then(Promise:D: &code)

Schedules a piece of code to be run after the invocant has been kept or
{'fraction_non_alphanumeric': 0.08507887251099043, 'fraction_numerical': 0.0062063615205585725, 'mean_word_length': 2.6763307984790874, 'pattern_counts': {'":': 0, '<': 38, '<?xml version=': 0, '>': 46, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4634237', 'n_tokens_mistral': 2265, 'n_tokens_neox': 2187, 'n_words': 1039}