Await Expressions

An await expression can be used to write asynchronous code in a linear fashion. It can be applied to methods that return a Task or Future, as well as to methods that expect a callback closure as final parameter.

Code can be written as if the methods in question return a value right away, and the compiler will handle the task of unwrapping the provided code and handle the callbacks properly. Under the hood, await will break the method into different parts, scheduling them to be executed asynchronously once the awaited actions have been completed.

Await with Tasks

Await with Tasks works similar to the "async/await" pattern in other non-Elements languages, such as JavaScript or Visual C#. A method is declared as returning a special Task type either explicitly, or using language sugar such as the C# async keyword. The returned Task instance can be used to keep track of the status, and be notified when the result is available – which the await keyword abstracts:

method Test: Task<String>;
begin
  var task := new Task<String>(-> begin
      Thread.Sleep(10000);
      exit 'Result!'
    end);
  task.Start();
  exit task;
end;

...

method OtherMethod();
begin
  var lMessage := await Test();
  writeLn(lMessage);
end;

At the point of the await in OtherMethod, the actual method containing the await call will finish. All subsequent code (such as the call to writeLn in the example above) will be wrapped in a helper type, and execute once the task as completed.

Await with Closures

Await can also be used with methods that take a "callback" closure as last parameter. The parameters of the closure will turn into return values of the call. For example consider the following call using Elements RTL's Http class:

method DownloadData;
begin
  Http.ExecuteRequestAsJson(new HttpRequest(URL), (aResponse) -> begin
    if assigned(aResponse.Content) then begin
      dispatch_async(dispatch_get_main_queue(), () -> begimn
        // show data
      end);
    end;
  end);
end;

This code uses two nested closures, first to wait for the response of tne network request, and then to process its results on the main UI thread. With await this can be unwrapped nicely:

method DownloadData;
begin
  var lResponse := await Http.ExecuteRequestAsJson(new HttpRequest(URL));
  if assigned(lResponse.Content) then begin
    await dispatch_async(dispatch_get_main_queue());
    // show data
  end;
end;

Note how the parameter of the first closure, aResponse becomes a local variable, lResponse, and how await is used without return value on the dispatch_async call.

For callbacks that return more than one parameter, await will return a Tuple, e.g.:

var (aValue, aError) := await TryToGetValueOrReturnError();
...

Await with Asynchronous Sequences

On the .NET platform, await can also be used to loop an Asynchronous Sequence. Here the await keyword is followed by the for each keywords defining a regular for Loop. Each individual entry in the sequence will be await'ed and the loop will be run for it. Execution after the loop will continue after all items have been processed and the end of the asynchronous sequence has been reached.

var lItems: async sequence of String := ...;

await for each i in lItems do
  writeLn(el);
writeLn("Done");

See Also

Await for Closure Callbacks is unique to Elements, and is available in RemObjects C# and Swift, as well.