Promise
From Erights
A promise, in E, is a kind of unresolved eventual ref. It is a ref which will resolve to some other ref later; therefore all sends it receives are stored, then forwarded at the time of the resolution. Every promise has a corresponding resolver (though it might be implicit), which constitutes the permission to cause it to resolve to a given other reference (which may itself be a promise).
A local promise is a promise whose resolver is in this vat; local promises are reliably implemented by the local ELib. A remote promise is a promise whose resolver is in a different vat; remote promises are implemented by proxies.
Local promises
The general-purpose operation to create a local promise is Ref#promise/0.
? def [promise, resolver] := Ref.promise() # value: [<Promise>, <Resolver>] ? Ref.state(promise) # value: "EVENTUAL" ? Ref.isResolved(promise) # value: false
Once a promise (local or remote) is resolved, it is indistinguishable from the reference which it is resolved to, whether that reference is Selfless,
? resolver.resolve(99) ? promise # value: 99 ? promise + 1 # value: 100 ? promise == 99 # value: true
or Selfish.
? def [promise, resolver] := Ref.promise() > resolver.resolve(def x {}) > promise == x # value: true
XXX write tests and doc from the LocalResolver's perspective (isDone, resolveRace/smash, behavior after it is resolved) -- EoCL has some in ref.updoc
Calls and sends
? def [promise, resolver] := Ref.promise(); null
As with any unresolved ref, a promise cannot be called.
? promise(1) # problem: not synchronously callable: <Promise>.run(1)
However, any sends to the promise are accepted and buffered in the resolver, in time order.
? promise <- (2) # value: <Promise> ? E.sendOnly(promise, "run", [3])
If the resolver becomes garbage, then so does the buffer; future messages to the promise are silently discarded and do not accumulate. Note that this implies that the promise does not strongly refer to the resolver. (XXX write tests for this using finalizers.)
At the instant a local promise is resolved to another ref (which is known as its resolution), the buffered messages are sent, in the order they arrived, to the resolution.
? var items := [] > def resolution(x) { items with= x } > resolution <- (4) # demonstrating exact ordering > def resolveReturn := resolver.resolve(resolution) > resolution <- (5) > resolveReturn ? items # value: [4, 2, 3, 5]