Asynchronous Operations: Blocks

Inside a lengthy async function, it's generally a good idea to group together data fetches that are independent of the rest of the function. This reduces unneeded waiting for I/O.

To express this grouping inline, we would usually have to use a helper function; however, an async block allows for the immediate execution of a grouping of code, possibly within zero-argument, async lambdas.

Syntax

The syntax for an async block is:

async {
  // grouped together calls, usually await.
  < statements >
}

Usage

Async blocks have two main use-cases. Remember, this is essentially syntactic sugar to make life easier.

  • Inline simple async statements that would before have required a function call to execute.
  • Replace the call required by an async lambda to return an actual Awaitable<T>.
async function gen_int(): Awaitable<int> {
  return 4;
}

async function gen_float(): Awaitable<float> {
  return 1.2;
}

async function gen_string(): Awaitable<string> {
  return "Hello";
}

async function gen_call<Tv>((function(): Awaitable<Tv>) $gen): Awaitable<Tv> {
  return await $gen();
}

async function use_async_lambda(): Awaitable<void> {
  // To use an async lambda with no arguments, you would need to have a helper
  // function to return an actual Awaitable for you.
  $x = await gen_call(
    async () ==> {
      $y = await gen_float();
      $z = await gen_int();
      return \round($y) + $z;
    },
  );
  \var_dump($x);
}

async function use_async_block(): Awaitable<void> {
  // With an async block, no helper function is needed. It is all built-in to the
  // async block itself.
  $x = await async {
    $y = await gen_float();
    $z = await gen_int();
    return \round($y) + $z;
  };
  \var_dump($x);
}

async function call_async_function(): Awaitable<void> {
  // Normally we have to call a simple async function and get its value, even
  // if it takes no arguments, etc.
  $x = await gen_string();
  \var_dump($x);
}

async function use_async_block_2(): Awaitable<void> {
  // Here we can inline our function right in the async block
  $x = await async {
    return "Hello";
  };
  \var_dump($x);
}

<<__EntryPoint>>
function main(): void {
  \HH\Asio\join(use_async_lambda());
  \HH\Asio\join(use_async_block());
  \HH\Asio\join(call_async_function());
  \HH\Asio\join(use_async_block_2());
}
Output
float(5)
float(5)
string(5) "Hello"
string(5) "Hello"

Limitations

The typechecker does not allow the use of an async block immediately on the right-hand side of the ==> in a lambda-creation expression.

In async named-functions, async immediately precedes function, which, in turn, immediately precedes the parameters. In async lambdas, async also immediately precedes the parameters.

So:

$x = async () ==> { ... } // good
$x = () ==> async { ... } // bad

Basically, this is just a safety guard to reduce the likelihood of unintended behavior.