Rules / Types, classes & roles / domain-specific

Promise Reference

Status/result of an asynchronous computation

What it is #

Routines #

Signatures are reproduced from the documentation, including their declared return types. A routine listed here is part of the type's published interface; whether Raku++ implements it is a separate question, answered by the examples below.

method start #

method start(Promise:U: &code, :$scheduler = $*SCHEDULER --> Promise:D)

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 result method. The scheduler that handles this promise can be passed as a named argument. There is also a statement prefix start that provides syntactic sugar for this method: As of the 6.d version of the language, start statement prefix used in

method in #

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

Returns Promise:D.

Creates a new Promise that will be kept in $seconds seconds, or later. $seconds can be fractional or negative. Negative values are treated as 0 (i.e. keeping the returned Promise right away). Please note that situations like these are often more clearly handled with a react and whenever block.

method at #

method at(Promise:U: $at, :$scheduler = $*SCHEDULER --> Promise:D)

Returns Promise:D.

Creates a new Promise that will be kept $at the given time—which is given as an Instant or equivalent Numeric—or as soon as possible after it. If the given time is in the past, it will be treated as now (i.e. keeping the returned Promise right away). Please note that situations like these are often more clearly handled with

method kept #

multi method kept(Promise:U: \result = True --> Promise:D)

Returns Promise:D.

Returns a new promise that is already kept, either with the given value, or with the default value True.

method broken #

multi method broken(Promise:U: --> Promise:D)
multi method broken(Promise:U: \exception --> Promise:D)

Returns Promise:D.

Returns a new promise that is already broken, either with the given value, or with the default value X::AdHoc.new(payload => "Died")

method allof #

method allof(Promise:U: *@promises --> Promise:D)

Returns Promise:D.

Returns a new promise that will be kept when all the promises passed as arguments are kept or broken. The result of the individual Promises is not reflected in the result of the returned promise: it simply indicates that all the promises have been completed in some way. If the results of the individual promises are important then they should be inspected after the allof promise is kept. In the following requesting the result of a broken promise will cause the

method anyof #

method anyof(Promise:U: *@promises --> Promise:D)

Returns Promise:D.

Returns a new promise that will be kept as soon as any of the promises passed as arguments is kept or broken. The result of the completed Promise is not reflected in the result of the returned promise which will always be Kept. You can use this to wait at most a number of seconds for a promise:

method then #

method then(Promise:D: &code)

Schedules a piece of code to be run after the invocant has been kept or broken, and returns a new promise for this computation. In other words, creates a chained promise. The Promise is passed as an argument to the &code.

method keep #

multi method keep(Promise:D: \result = True)

Keeps a promise, optionally setting the result. If no result is passed, the result will be True. Throws an exception of type X::Promise::Vowed if a vow has already been taken. See method vow for more information.

method break #

multi method break(Promise:D: \cause = False)

Breaks a promise, optionally setting the cause. If no cause is passed, the cause will be False. Throws an exception of type X::Promise::Vowed if a vow has already been taken. See method vow for more information.

method result #

method result(Promise:D:)

Waits for the promise to be kept or broken. If it is kept, returns the result; otherwise throws the result as an exception.

method cause #

method cause(Promise:D:)

If the promise was broken, returns the result (or exception). Otherwise, throws an exception of type X::Promise::CauseOnlyValidOnBroken.

method Bool #

multi method Bool(Promise:D:)

Returns True for a kept or broken promise, and False for one in state Planned.

method status #

method status(Promise:D --> PromiseStatus)

Returns PromiseStatus.

Returns the current state of the promise: Kept, Broken or Planned: See PromiseStatus.

method scheduler #

method scheduler(Promise:D:)

Returns the scheduler that manages the promise.

method vow #

method keep() { ... }
method break() { ... }
method vow(Promise:D: --> Vow:D)

Returns Vow:D.

Returns an object that holds the sole authority over keeping or breaking a promise. Calling keep or break on a promise that has vow taken throws an exception of type X::Promise::Vowed.

method Supply #

method Supply(Promise:D:)

Returns a Supply that will emit the result of the Promise being Kept or quit with the cause if the Promise is Broken.

sub await #

multi await(Promise:D --> Promise)
multi await(*@ --> Array)

Returns Promise or Array.

Waits until one or more promises are all fulfilled, and then returns their values. Also works on Channels. Any broken promises will rethrow their exceptions. If a list is passed it will return a list containing the results of awaiting each item in turn.

Examples, run three ways #

Every example below comes from the official documentation, together with the output that documentation asserts. Each was then executed by Rakudo and by Raku++ when this page was built. Where the three agree, one result is shown; where they do not, all three are — because which of them is wrong is exactly the information worth having.

2 all-differ · 3 doc-drift · 14 no-output · 2 not-runnable · 1 ok · 1 rakudo-differs

class Promise {}

Not executed: the documentation states no expected output for this example.

my $p = Promise.start({ sleep 2; 42});
$p.then({ say .result });   # will print 42 once the block finished
say $p.status;              # OUTPUT: «Planned␤»
$p.result;                  # waits for the computation to finish
say $p.status;              # OUTPUT: «Kept␤»
Documentation
Planned
Kept
Rakudo
Planned
Kept
42
Raku++
Planned
42
Kept

All three differ. Needs a human.

Not yet examined. Which of these is correct has not been established — do not treat either engine as settled here.

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;
}

Not executed: the documentation states no expected output for this example.

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

Not executed: the documentation states no expected output for this example.

=begin code :solo
use v6.c;
start { die }; sleep ⅓; say "hello"; # OUTPUT: «hello␤»
=end code
Documentation
hello
Rakudo
Raku++

Both engines agree; the documentation states something else. Trust the engines.

=begin code :solo
use v6.d;
start { die }; sleep ⅓; say "hello";
# OUTPUT:
# Unhandled exception in code scheduled on thread 4
# Died
#     in block  at -e line 1
=end code

Not executed: the documentation states no expected output for this example.

=begin code
# Don't sink it:
my $ = start { die }; sleep ⅓; say "hello"; # OUTPUT: «hello␤»
Documentation
hello
Rakudo
Raku++

Both engines agree; the documentation states something else. Trust the engines.

# Catch yourself:
start { die; CATCH { default { say "caught" } } };
sleep ⅓;
say "hello";
# OUTPUT: «caught␤hello␤»
=end code
Documentation
caught
hello
Rakudo
Raku++
caught
hello

Raku++ matches the documentation; Rakudo does not. This is the one class where neither engine can be assumed right: it may be a stale doc that Raku++ was built from, or it may be a Rakudo bug that the documentation predates. Each case is examined individually.

Not yet examined. Which of these is correct has not been established — do not treat either engine as settled here.

my $proc = Proc::Async.new('raku', '-e', 'sleep 10; warn "end"');

Not executed: the documentation states no expected output for this example.

my $result = await Promise.anyof(
    my $promise = $proc.start,  # may or may not work in time
    Promise.in(5).then: {       # fires after 5 seconds no matter what
        unless $promise {       # don't do anything if we were successful
            note 'timeout';
            $proc.kill;
        }
    }
).then: { $promise.result }
# OUTPUT: «timeout␤»

Neither engine can run this in isolation — the example depends on context from the surrounding text.

my $p = Promise.at(now + 2).then({ say "2 seconds later" });
# do other stuff here

Not executed: the documentation states no expected output for this example.

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

Not executed: the documentation states no expected output for this example.

my @promises;
for 1..5 -> $t {
    push @promises, start {
        sleep $t;
    };
}
my $all-done = Promise.allof(@promises);
await $all-done;
@promises>>.result;
say "Promises kept so we get to live another day!";

Not executed: the documentation states no expected output for this example.

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

Not executed: the documentation states no expected output for this example.

# Use code only
my $timer = Promise.in(2);
my $after = $timer.then({ say '2 seconds are over!'; 'result' });
say $after.result;
# OUTPUT: «2 seconds are over␤result␤»
Documentation
2 seconds are over
result
Rakudo
2 seconds are over!
result
Raku++
2 seconds are over!
result

Both engines agree; the documentation states something else. Trust the engines.

# Interact with original Promise
my $after = Promise.in(2).then(-> $p { say $p.status; say '2 seconds are over!'; 'result' });
say $after.result;
# OUTPUT: «Kept␤2 seconds are over␤result␤»
Documentation
Kept
2 seconds are over
result
Rakudo
Kept
2 seconds are over!
result
Raku++
Planned
2 seconds are over!
result

All three differ. Needs a human.

Not yet examined. Which of these is correct has not been established — do not treat either engine as settled here.

my $p = Promise.new;

Not executed: the documentation states no expected output for this example.

if Bool.pick {
    $p.keep;
}
else {
     $p.break;
}

Not executed: the documentation states no expected output for this example.

my $p = Promise.new;

Not executed: the documentation states no expected output for this example.

$p.break('sorry');
say $p.status;          # OUTPUT: «Broken␤»
say $p.cause;           # OUTPUT: «sorry␤»

Neither engine can run this in isolation — the example depends on context from the surrounding text.

say "promise got Kept" if $promise.status ~~ Kept;

Not executed: the documentation states no expected output for this example.

my class Vow {
has Promise $.promise;
}

Not executed: the documentation states no expected output for this example.

my $p   = Promise.new;
my $vow = $p.vow;
$vow.keep($p);
say $p.status;          # OUTPUT: «Kept␤»
Output
Kept

Documentation, Rakudo and Raku++ all agree.