Future Types

Future Types are a language concept unique to Oxygene that are designed to facilitate Parallel Computing and developing applications that scale well on multi-core and multi-CPU systems.

A future is a strongly typed variable that represents a value that might or might not have been calculated yet, but is guaranteed to be (made) available when needed. Consider the following snippet of pseudo code that calculates the Sum of values in a binary tree:

method ThreeNode.Sum: Integer;
begin
  var l := Left.Sum;
  var r := Right.Sum;
  result := l+r;
end;

This code first calculates the Sum of the left part of the subtree, then that of the right one. Finally, the two values are combined using the + operator. Calculating the value of both l and r might take a relatively long time, yet the value of l is not actually needed until the very last line of the method. This is an ideal candidate for a future:

method ThreeNode.Sum: Integer;
begin
  var l: future Integer := async Left.Sum;
  var r: Integer := Right.Sum;
  result := l+r;
end;

Instead of calculating the value of l in place as before, l is now defined as a future Integer, declaring that the variable does not actually hold the value of Left.Sum, but just the promise that, at some point in the future, it will. This first line of code will execute in virtually no time, and the method can move on to calculating r, which is unchanged and will happen inline, as before.

Note how the value assigned to l has been changed to include the async keyword, making it an async expression that will be spawned in the background. In fact, it's this use of the async keyword that defines the future, and the same would happen without the explicit type declarations:

method ThreeNode.Sum: Integer;
begin
  var l := async Left.Sum; // l will become a future Integer
  var r := Right.Sum;      // r is still a regular Integer
  result := l+r;
end;

The actual value of the future, l in this example, will not be accessed until it is used in code. In the code above, this happens on the last line of the method, when l is used with the + operator to combine with with r.

When the value is accessed, one of three things can happen:

  • If the future is already done executing in the background, its value will be available immediately, just as if it were a plain non-future type that is being accessed.
  • If the future is not finished executing at that point, execution will hold and block the current thread until the future is done.
  • If any exception occurred while executing the future in the background, that exception will be re-thrown as the future value is accessed.

Note how in the example above, the code does not need to worry about whether the value of the future l has already been determined or not when execution reaches the last line and the value is required. The code can simply treat l as if it were a regular Integer.

Type-Less Futures

Futures can also be type-less, also referred to as Void Futures. Such a type-less future does not represent a value, but merely a certain action that will be run in the background.

A type-less future can be called, like a statement, in order to wait for its action to be finished. But because a type-less future has no value, it cannot be used as an expression, only as a statement.

var fut := async begin   // goes off and does a couple of things in the background
             DoSomething();
             DoSomethingElse();
           end;

DoSomeMore(); // meanwhile, do more work on the current thread

fut(); // wait for the type-less future to finish, if it hasn't already.
var x := fut(); // ERROR. fut has no value.

As with typed futures, if any exception occurred in the background while executing the future, that exception will be re-thrown if and when the future is being called into.

Non-Asynchronous Futures

While asynchronous futures are the most common use case, a future type in itself does not imply background execution – it merely implies a value that may or may not exist, and will be made available when needed.

If a future is declared and initialized with an expression that is not an async expression, the value will be calculated the first time it is accessed.

method ThreeNode.Sum: Integer;
begin
  var valueA := SomeCostlyOperation();
  var valueB := SomeOtherCostlyOperation();

  // ...

  if x > 10 then
    result := SomeCostlyOperation + SomeOtherCostlyOperation; // SomeCostlyOperation will only
  else                                                    // be calculated if we hit this line
    result := SomeOtherCostlyOperation;

  result := result*SomeOtherCostlyOperation; // in any case, SomeOtherCostlyOperation is only
end;                                         // calculated once

A Futures Executes only Once

Both typed and type-less futures will only execute a single time.

The value of a typed future may be accessed multiple times during the flow of execution; the first time it is accessed, the code will wait for the future to be calculated, if necessary. Subsequent access will simply yield the value directly.

Similarly, the first time you call into a type-less future, execution will wait if needed; subsequent calls will be guaranteed to just return immediately.

method ThreeNode.WeirdSum: Integer;
begin
  var l := async Left.Sum;
  var r := Right.Sum;
  result := l+r+l; // l will only be calculated once, even though it's being accessed twice
end;

See Also