In short - It's possible to model with an Async Generator.
In the DB connection example, conceptually you've got a sequence of DB connections, every time you access the value you're yielding (possibly asynchronously) a value from the sequence (a connection). Yielding can be asynchronous, and the value itself might be asynchronous too. The sequence might end (making it never available again) or it might always yield the result - it might remain pending and never yield another connection again.
It's worth mentioning that an async generator is a vast superset of the type you're after - it's much more expressive and is not the diret inverse.
In long - Inverse how?
You could inverse a promise in several different ways.
A promise is a singular temporal getter. That is it holds the following:
- It represents a single value.
- Its value is temporal (that is, time dependant).
- It's a getter.
Quoting Kris's work on the temporality of promises:
An observer can subscribe to eventually see the value of a promise. They can do this before or after the promise has a value. Any number of observers can subscribe multiple times and any single observer can subscribe to the same promise multiple times.... Promises are broadcast. The law that no consumer can interfere with another consumer makes it impossible for promises to abort work in progress. A promise represents a result, not the work leading to that result.
The inverse of a promise in each of these regards is different.
A Deferred is a singular temporal setter. It is the dual of a promise and it allows setting a value similarly to how a promise allows getting it.
A Reader (more commonly called an observable) is the multiple version of a promise, and the temporal version of an iterable. It represents multiple values that are temporally coming. It's like a promise that can change its value.
A Value , one of out most used and primitive things is the synchronous version of a promise.
If you want something that is unlike a promise in all three - you need something more advanced. A Generator, is the inverse of a promise in that regard, it's a spatial, multivalued setter. It's the opposite of a promise in every such regard.
However, what you're talking of is something that's async in both regards, you want something that is both available/unavailable and changes value. That's an async generator, one of the more complex types in play here.
Your type needs to be similar to a generator that's async twice, once in having the next value and once in getting the value itself, I've asked a similar C# question here. Here is an interesting talk and lecture about it.
Basically you want a generator whose values and next()
are asynchronous. It's rather complex and there are few things it models properly (for example - an infinite scroll where both the scrolling and the content are asynchronous).
In a sense, the sequence ending signals your value "not being available" anymore, and the sequence generating the next instance indicates your signal not being available temporally again.
I also recommend Erik Meijer's talk and Kris Kowal's GTOR about this subject.
{data = value, ended = Promise<null>}
(and indeed it is how I've currently implemented it). However, it feels wrong, becausedata
- the connection - can always be accessed, and because the promise doesn't represent a value. – PollyObservable
calleddeath
or whatever to signal the end-of-life for the Observer and then instead of subscribing to thesubject
I subscribe tosubject.takeUntil(death)
." – Polly