essenceDocumentation
essenceDocs
on this pageAt a glance
Coming from JavaScript?

Future

type

Work that has not run: a description to start, and one run of it to wait for.

A description of work that will answer with a Value.

Building one runs nothing. start puts it in flight and answers the one run of it, and complete waits for what it answers with. A Future can be started any number of times, and each start is a fresh run.

A Function whose body writes complete declares -> Future<Value>. Calling it is an ordinary call that builds the future without running any of it.

Taught on: Asynchrony.

At a glance

Declared
namespace Future<infer Value> for Future<Value>
Views

A view is a namespace for a narrower type. A value of that type has the view's methods on top of its own.

Describing work

deferred

on Async

static deferred<infer Value>(_ compute: () -> Value) -> Future<Value>

Answers a Future that runs the given Function when it is started.

Nothing runs while the Future is being built. Each start calls the Function again, so two starts answer two values, and a Function reading something that changes reads it at each start.

The Function runs on the Program's own thread, from beginning to end, with nothing else in between. It is the way to describe a computation as work rather than to carry one out somewhere else.

NameTypeDescription
_() -> Valuethe computation to run when the Future is started

a Future answering what the computation answers.

Example
variable starts = 0

constant counted = Async.deferred(() {
	starts = starts::add(1)

	<- starts
})

expect starts::is(0)

constant first = complete counted
constant second = complete counted

expect first::is(1)
expect second::is(2)

sleep

on Async

static sleep(milliseconds duration: Integer) -> Future<{}>

Answers a Future that waits the given number of milliseconds.

Nothing waits while the Future is being built. Each start waits again, so a Future that is started twice waits twice.

A wait that is stopped never answers. The runs that within and race leave behind are stopped, and what one would have answered is never read.

NameTypeDescription
millisecondsIntegerhow long to wait

a Future answering nothing, once the time has passed.

Building on a Future

map

on Future<Value>

map<infer Other>(_ transform: (_: Value) -> Other) -> Future<Other>

Answers a Future that runs this one and hands its value to the transform.

Nothing runs while the answer is being built. Each start of the answer starts the receiver again, so two starts run the work twice and call the transform twice.

NameTypeDescription
_(_: Value) -> Otherthe transform the value is handed to

a Future answering what the transform answers.

Example
constant price = Async.deferred(() { <- 40 })
constant total = complete price::map((amount) { <- amount::add(2) })

expect total::is(42)

on Started<Value>

map<infer Other>(_ transform: (_: Value) -> Other) -> Started<Other>

Answers the same run, with its value handed to the transform.

The work is in flight already and nothing here starts it again, so the transform runs once however often the answer is completed.

NameTypeDescription
_(_: Value) -> Otherthe transform the value is handed to

the run, answering what the transform answers.

Example
constant run = start Async.deferred(() { <- 20 })
constant doubled = complete run::map((n) { <- n::multiply(with 2) })

expect doubled::is(40)

andThen

on Future<Value>

Answers a Future that runs this one, and then work that follows it.

a Future answering what the work that follows answers.

andThen<infer Other>(
	_ next: (_: Value) -> Future<Other>,
) -> Future<Other>

Answers a Future that runs this one, and then the one the next Function builds from its value.

The Function is called once the receiver has answered, so what it builds can read that value. Nothing runs while the answer is being built.

NameTypeDescription
_(_: Value) -> Future<Other>the Function building the work to run next

a Future answering what the next work answers.

Example
constant userId = Async.deferred(() { <- 7 })
constant greeting = complete userId::andThen((id) {
	<- Async.deferred(() { <- "Hello, user {id}" })
})

expect greeting::is("Hello, user 7")
andThen<infer Other>(_ next: Future<Other>) -> Future<Other>

Answers a Future that runs this one, and then the given one.

The value the receiver answers with is dropped. This is the entry for work run for its effect, where what comes next does not read it.

NameTypeDescription
_Future<Other>the work to run once the receiver has answered

a Future answering what the given work answers.

Example
constant save = Async.deferred(() { <- "saved" })
constant notify = Async.deferred(() { <- "notified" })
constant answer = complete save::andThen(notify)

expect answer::is("notified")

within

on Future<Value>

within(milliseconds limit: Integer) -> Future<Optional<Value>>

Answers a Future that runs this one, and answers nothing where it takes too long.

The run is stopped at the deadline. It was started by this Method and nothing else can be waiting for it, so what it would have answered is never read.

The answer is an Optional rather than a failure, because a deadline is a question the caller asked rather than something that went wrong.

NameTypeDescription
millisecondsIntegerhow long the run has

the value, or nothing where the deadline passed first.

Example
constant quick = Async.deferred(() { <- "ready" })
constant answer = complete quick::within(milliseconds 1000)

expect answer::is("ready")

on Started<Value>

within(milliseconds limit: Integer) -> Started<Optional<Value>>

Answers the same run, giving up on it after the given number of milliseconds.

The run is not stopped. A Started can be completed from anywhere, so a deadline one holder writes can not stop the work another is waiting for. The waiting stops and the work goes on.

A host with an event loop stays open until that work is over. Giving up on an answer is not giving up on the run, so a Program can not exit ahead of it.

The time is counted from here, because the run is in flight already.

NameTypeDescription
millisecondsIntegerhow long to wait for it

the value, or nothing where the deadline passed first.

Example
constant run = start Async.deferred(() { <- "ready" })
constant answer = complete run::within(milliseconds 1000)

expect answer::is("ready")

attempt

on Future<Result<Value, Failure>>

Answers a Future that runs this one again while it fails, up to the given number of attempts.

a Future answering the first value, or the last reason.

attempt(times count: Integer) -> Future<Result<Value, Failure>>

Answers a Future that runs this one until it answers a value, up to the given number of attempts.

The first attempt is one of the count, so attempt(times 3) runs the work three times at worst. A count below two is one attempt.

The answer is the first value, or the last reason where every attempt failed.

NameTypeDescription
timesIntegerhow many attempts to make in all

a Future answering the first value, or the last reason.

Example
variable calls = 0

constant flaky = Async.deferred(() -> Result<Integer, String> {
	calls = calls::add(1)

	if calls::isLessThan(3) {
		<- #Failure("busy on call {calls}")
	}

	<- #Value(calls)
})

constant gaveUp = complete flaky::attempt(times 2)
constant answered = complete flaky::attempt(times 5)

expect gaveUp::is(#Failure("busy on call 2"))
expect answered::is(3)
attempt(
	times count: Integer,
	pausingMilliseconds pause: Integer,
) -> Future<Result<Value, Failure>>

Answers the same, waiting the given number of milliseconds between two attempts.

The wait is between attempts, and never before the first or after the last.

NameTypeDescription
timesIntegerhow many attempts to make in all
pausingMillisecondsIntegerhow long to wait between two attempts

a Future answering the first value, or the last reason.

Example
constant ready = Async.deferred(() -> Result<String, String> {
	<- #Value("saved")
})

constant answer = complete ready::attempt(
	times 3,
	pausingMilliseconds 200,
)

expect answer::is("saved")

Several at once

inSequence

on List<Future<Value>>

inSequence() -> Future<List<Value>>

Answers a Future running every one of them in order, each started once the one before it has answered.

The answer holds one value per item, in the receiver's order. The empty List answers the empty List.

This is the entry for work that is not independent. A host can refuse a second request at once, and a walk can have an order that is what the answer means.

a Future answering the List of values.

Example
constant steps = [
	Async.deferred(() { <- "fetch" }),
	Async.deferred(() { <- "parse" }),
]
constant none: List<Future<String>> = []

constant done = complete steps::inSequence()
constant nothing = complete none::inSequence()

expect done::is(["fetch", "parse"])
expect nothing::isEmpty()

all

on List<Future<Value>>

Answers a Future starting them at once, or a few at a time, and answering their values in the receiver's order.

a Future answering the List of values.

all() -> Future<List<Value>>

Answers a Future starting every one of them at once, and answering their values in the receiver's order.

The order of the answer is the receiver's, whatever order the runs finish in. The empty List answers the empty List.

Everything runs on the Program's own thread, so what this saves is the waiting rather than the computing.

a Future answering the List of values.

Example
constant lookups = [
	Async.deferred(() { <- "Ada" }),
	Async.deferred(() { <- "Grace" }),
]
constant names = complete lookups::all()

expect names::is(["Ada", "Grace"])
all(atMost count: Integer) -> Future<List<Value>>

Answers the same, with at most the given number of runs in flight at once.

A count below one runs them one at a time, and a count above the length runs them all at once.

NameTypeDescription
atMostIntegerhow many runs to have in flight at once

a Future answering the List of values.

Example
constant pages = [
	Async.deferred(() { <- 1 }),
	Async.deferred(() { <- 2 }),
	Async.deferred(() { <- 3 }),
]
constant numbers = complete pages::all(atMost 2)

expect numbers::is([1, 2, 3])

race

on NonEmptyList<Future<Value>>

race() -> Future<Value>

Answers a Future starting every one of them at once, and answering with the first value any of them answers.

Every other run is stopped as soon as one has answered. What a stopped run would have answered is never read.

a Future answering the first value.

Example
constant quick = Async.deferred(() { <- "quick" })
constant slow = Async.sleep(milliseconds 60000)::map((_) {
	<- "slow"
})

constant first = complete [slow, quick]::race()

expect first::is("quick")

firstValue

on List<Future<Result<Value, Failure>>>

firstValue() -> Future<Optional<Value>>

Answers a Future starting every one of them at once, and answering with the value of the first that answers one.

A run that fails is not an answer, and the waiting goes on. Every other run is stopped as soon as one has answered a value.

A List whose every run failed answers nothing, and so does the empty List. The name is OptionalList::firstValue's, for the same question one level along.

the first value, or nothing where every run failed.

Example
constant down: Result<String, String> = #Failure("down")
constant up: Result<String, String> = #Value("mirror")

constant mirrors = [
	Async.deferred(() { <- down }),
	Async.deferred(() { <- up }),
]
constant failing = [Async.deferred(() { <- down })]

constant found = complete mirrors::firstValue()
constant missing = complete failing::firstValue()

expect found::is("mirror")
expect missing::isEmpty()

Reading a run

map on Started<Value> is listed under map, with the other entries of that name.

within on Started<Value> is listed under within, with the other entries of that name.

esc