txt: ## promise.md
  class Promise
  
  Status/result of an asynchronous computation
  
  ```raku
  my enum PromiseStatus (:Planned(0), :Kept(1), :Broken(2));
  class Promise {}
  ```
  
  A `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 `then` method), execution after a time delay (with `in`), combining promises, and waiting for results.
  
  ```raku
  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␤»
  ```
  
  There are two typical scenarios for using promises. The first is to use a factory method (`start`, `in`, `at`, `anyof`, `allof`, `kept`, `broken`) on the type object; those will make sure that the promise is automatically kept or broken for you, and you can't call `break` or `keep` on these promises yourself.
  
  The second is to create your promises yourself with `Promise.new`. If you want to ensure that only your code can keep or break the promise, you can use the `vow` method to get a unique handle, and call `keep` or `break` on it:
  
  ```raku
  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;
  }
  
  ```
  
  Further examples can be found in the [concurrency page](/language/concurrency#Promises).
  
  # [Methods](#class_Promise "go to top of document")[§](#Methods "direct link")
  
  ## [method start](#class_Promise "go to top of document")[§](#method_start "direct link")
  
  ```raku
  method start(Promise:U: &code, :$scheduler = $*SCHEDULER --> 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:
  
  ```raku
  # these two are equivalent:
  my $p1 = Promise.start({ ;#`( do something here ) });
  my $p2 = start { ;#`( do something here ) };
  ```
  
  As of the 6.d version of the language, `start` statement prefix used in [sink](/routine/sink) context will automatically attach an exceptions handler. If an exception occurs in the given code, it will be printed and the program will then exit, like if it were thrown without any `start` statement prefixes involved.
  
  ```raku
  use v6.c;
  start { die }; sleep ⅓; say "hello"; # OUTPUT: «hello␤»
  
  ```
  
  ```raku
  use v6.d;
  start { die }; sleep ⅓; say "hello";
  # OUTPUT:
  # Unhandled exception in code scheduled on thread 4
  # Died
  #     in block  at -e line 1
  
  ```
  
  If you wish to avoid this behavior, use `start` in non-sink context or catch the exception yourself:
  
  ```raku
  # Don't sink it:
  my $ = start { die }; sleep ⅓; say "hello"; # OUTPUT: «hello␤»
  
  # Catch yourself:
  start { die; CATCH { default { say "caught" } } };
  sleep ⅓;
  say "hello";
  # OUTPUT: «caught␤hello␤»
  
  ```
  
  This behavior exists only syntactically, by using an alternate `.sink` method for `Promise` objects created by `start` blocks in sink context, thus simply sinking a `Promise` object that was created by other means won't trigger this behavior.
  
  ## [method in](#class_Promise "go to top of document")[§](#method_in "direct link")
  
  ```raku
  method in(Promise:U: $seconds, :$scheduler = $*SCHEDULER --> Promise:D)
  ```
  
  Creates a new Promise that will be kept in `$seconds` seconds, or later.
  
  ```raku
  my $proc = Proc::Async.new('raku', '-e', 'sleep 10; warn "end"');
  
  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␤»
  ```
  
  `$seconds` can be fractional or negative. Negative values are treated as `0` (i.e. [keeping](/routine/keep) the returned `Promise` right away).
  
  Please note that situations like these are often more clearly handled with a [react and whenever block](/language/concurrency#react).
  
  ## [method at](#class_Promise "go to top of document")[§](#method_at "direct link")
  
  ```raku
  method at(Promise:U: $at, :$scheduler = $*SCHEDULER --> Promise:D)
  ```
  
  Creates a new `Promise` that will be kept `$at` the given time—which is given as an [`Instant`](/type/Instant) or equivalent [`Numeric`](/type/Numeric)—or as soon as possible after it.
  
  ```raku
  my $p = Promise.at(now + 2).then({ say "2 seconds later" });
  # do other stuff here
  
  await $p;   # wait here until the 2 seconds are over
  ```
  
  If the given time is in the past, it will be treated as [now](/routine/now) (i.e. [keeping](/routine/keep) the returned `Promise` right away).
  
  Please note that situations like these are often more clearly handled with a [react and whenever block](/language/concurrency#react).
  
  ## [method kept](#class_Promise "go to top of document")[§](#method_kept "direct link")
  
  ```raku
  multi method kept(Promise:U: \result = True --> Promise:D)
  ```
  
  Returns a new promise that is already kept, either with the given value, or with the default value `True`.
  
  ## [method broken](#class_Promise "go to top of document")[§](#method_broken "direct link")
  
  ```raku
  multi method broken(Promise:U: --> Promise:D)
  multi method broken(Promise:U: \exception --> 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](#class_Promise "go to top of document")[§](#method_allof "direct link")
  
  ```raku
  method allof(Promise:U: *@promises --> 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 original Exception to be thrown. (You may need to run it several times to see the exception.)
  
  ```raku
  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!";
  ```
  
  ## [method anyof](#class_Promise "go to top of document")[§](#method_anyof "direct link")
  
  ```raku
  method anyof(Promise:U: *@promises --> 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:
  
  ```raku
  my $timeout = 5;
  await Promise.anyof(
      Promise.in($timeout),
      start {
          # do a potentially long-running calculation here
      },
  );
  ```
  
  ## [method then](#class_Promise "go to top of document")[§](#method_then "direct link")
  
  ```raku
  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`.
  
  ```raku
  # 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␤»
  
  # 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␤»
  ```
  
  ## [method keep](#class_Promise "go to top of document")[§](#method_keep "direct link")
  
  ```raku
  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`](/type/X/Promise/Vowed) if a vow has already been taken. See method `vow` for more information.
  
  ```raku
  my $p = Promise.new;
  
  if Bool.pick {
      $p.keep;
  }
  else {
       $p.break;
  }
  ```
  
  ## [method break](#class_Promise "go to top of document")[§](#method_break "direct link")
  
  ```raku
  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`](/type/X/Promise/Vowed) if a vow has already been taken. See method `vow` for more information.
  
  ```raku
  my $p = Promise.new;
  
  $p.break('sorry');
  say $p.status;          # OUTPUT: «Broken␤»
  say $p.cause;           # OUTPUT: «sorry␤»
  ```
  
  ## [method result](#class_Promise "go to top of document")[§](#method_result "direct link")
  
  ```raku
  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](#class_Promise "go to top of document")[§](#method_cause "direct link")
  
  ```raku
  method cause(Promise:D:)
  ```
  
  If the promise was broken, returns the result (or exception). Otherwise, throws an exception of type [`X::Promise::CauseOnlyValidOnBroken`](/type/X/Promise/CauseOnlyValidOnBroken).
  
  ## [method Bool](#class_Promise "go to top of document")[§](#method_Bool "direct link")
  
  ```raku
  multi method Bool(Promise:D:)
  ```
  
  Returns `True` for a kept or broken promise, and `False` for one in state `Planned`.
  
  ## [method status](#class_Promise "go to top of document")[§](#method_status "direct link")
  
  ```raku
  method status(Promise:D --> PromiseStatus)
  ```
  
  Returns the current state of the promise: `Kept`, `Broken` or `Planned`:
  
  ```raku
  say "promise got Kept" if $promise.status ~~ Kept;
  
  ```
  
  ## [method scheduler](#class_Promise "go to top of document")[§](#method_scheduler "direct link")
  
  ```raku
  method scheduler(Promise:D:)
  ```
  
  Returns the scheduler that manages the promise.
  
  ## [method vow](#class_Promise "go to top of document")[§](#method_vow "direct link")
  
  ```raku
  my class Vow {
      has Promise $.promise;
      method keep() { ... }
      method break() { ... }
  }
  method vow(Promise:D: --> 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`](/type/X/Promise/Vowed).
  
  ```raku
  my $p   = Promise.new;
  my $vow = $p.vow;
  $vow.keep($p);
  say $p.status;          # OUTPUT: «Kept␤»
  ```
  
  ## [method Supply](#class_Promise "go to top of document")[§](#method_Supply "direct link")
  
  ```raku
  method Supply(Promise:D:)
  ```
  
  Returns a [`Supply`](/type/Supply) that will emit the `result` of the `Promise` being Kept or `quit` with the `cause` if the `Promise` is Broken.
  
  ## [sub await](#class_Promise "go to top of document")[§](#sub_await "direct link")
  
  ```raku
  multi await(Promise:D --> Promise)
  multi await(*@ --> Array)
  ```
  
  Waits until one or more promises are *all* fulfilled, and then returns their values. Also works on [`Channel`](/type/Channel)s. 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.
  
  # [Typegraph](# "go to top of document")[§](#typegraphrelations "direct link")
  
  Type relations for `Promise`
  
  
  
  raku-type-graph
  
  
  
  Promise
  Promise
  
  
  Any
  Any
  
  
  Promise->Any
  
  
  
  Mu
  Mu
  
  
  Any->Mu
  
  [Expand chart above](/assets/typegraphs/Promise.svg)
  