8

A promise represents a value that might become available in the future (or fails to do so).

What I am looking for is a data type which represents an available value that might become unavailable in the future (possibly due to an error):

Promise a b = TransitionFromTo<PENDING, Either<value a, error b>>
??? a       = TransitionFromTo<value a, Either<ENDED, FAILED>> or
??? a b     = TransitionFromTo<value a, Either<ENDED, error b>>

Has such a concept (or similar) been explored already? Are there existing semantics or common idioms?

For example, it might represent an open database connection that will get closed. My particular use case would be representing a "mutable", i.e. variable-sized, set-like collections in FRP as a stream of such "ending values" - when an event occurs the value is added to the set and when the value "ends" it is removed.

I felt like representing this as a Signal<Option<value>> or {data = value, ended = Promise<null>} doesn't quite match it - the first case doesn't include the guarantee that the value finally settles to Nothing and the second has the data field still accessible after the end.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Your use case of a database connection being closed would seem to be just another future value (where what's important is not the value, but the fact of fulfillment) so why could it not represented by a regular old promise? –  Sep 28 '14 at 11:50
  • @torazaburo: Yes, that's what I meant with `{data = value, ended = Promise}` (and indeed it is how I've currently implemented it). However, it feels wrong, because `data` - the connection - can always be accessed, and because the promise doesn't represent a value. – Bergi Sep 28 '14 at 12:23
  • I'm far from any kind of promises expert, but it seems to me that promises don't *need* to have values, and in fact often the value is ignored. Can the value not be thought of as sort of a detail, additional information about the resolution? To me, promises where values are ignored have no code smell whatsover. –  Sep 28 '14 at 12:39
  • @torazaburo: Yes, that's true, there are a few use cases that ignore the value and just are interested in the temporal chaining; and for these sometimes promises are created that don't carry a value. This might indeed be used in an implementation of the type, but currently I'm looking for a name of such a (abstract) data structure that also carries the "before-settling" value. – Bergi Sep 28 '14 at 12:46
  • The first thing that came to mind is a weak reference, which can be used to access a value until it can't anymore. – dfeuer Sep 28 '14 at 16:36
  • Update: [In this answer](http://stackoverflow.com/a/26734408/1048572), the creator of Bacon.js says: "*Personally I often create an `Observable` called `death` or whatever to signal the end-of-life for the Observer and then instead of subscribing to the `subject` I subscribe to `subject.takeUntil(death)`.*" – Bergi Dec 03 '14 at 01:42

3 Answers3

8

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.

Community
  • 1
  • 1
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • I think I want to inverse the temporal component of the promise - it's like running it backwards from "has value" into "pending/unavailable". It should still be a single value, and a getter (the creator of the structure sets the value and determines when to end it). – Bergi Sep 28 '14 at 12:30
  • 1
    I see what you've done to the sequence of DB connections (I've read GTOR and found this async+async generator concept very interesting). However, the `next` event should *not* make the previous value unavailable, it should persist until it decides itself to end - think of pooling connections. My real-world use case is a collection of (reactive) childnodes which are created as stream events (by a generator so to say) and then should be removed from their parent once they "end". – Bergi Sep 28 '14 at 12:36
  • @Bergi I recall something relevant in http://dl.acm.org/citation.cfm?id=54016 (the original promises paper) but I can't open it here since I don't have my academic VPN handy here. So I'll check when I'm at the university - if you have access to the resource - have a look :) Edit: I've done something rather rude, maybe it'll bear fruit we'll have to wait and see. – Benjamin Gruenbaum Sep 28 '14 at 12:50
  • Yes, luckily I don't need my university VPN to access it :-) Do you know what exactly I should be looking for? PS: What did you consider rude? – Bergi Sep 28 '14 at 13:00
  • @Bergi can you [come here real quick?](http://chat.stackoverflow.com/rooms/17/javascript-ye-olde-js-chat) – Benjamin Gruenbaum Sep 28 '14 at 13:01
  • I'm not convinced in my answer. I'll do my best to formalize this with temporal logic, hopefully that'll turn up a thing or two. – Benjamin Gruenbaum Sep 29 '14 at 06:04
  • Yeah, me neither. Although I think a generator that `yield`s the value when asked while it is available and just `return`ing/`throw`ing when asked after it is unavailable could fit the requirements. – Bergi Sep 29 '14 at 12:42
2

A promise is an ordered triple:

Time -> Notification -> Value

Its inverse must also be an ordered triple:

Value -> Notification -> Time

However, you don't want to be notified when the value begins to decay, which is immediately; instead, you want to be notified when the value has decayed.

Value -> Time -> Notification

Notification carries Dispose semantics. Actually, it'd be quite similar to IDisposable if it were defined as IDisposable<T>.

public interface IDisposable<T out>
{
  T Value { get; }
  IDisposable Subscribe(Action disposedAction);
  void Dispose();  // Not entirely necessary, perhaps.
}

It looks like a Frankenstein hybrid of Task<T> and IObservable<T>.

The async dual of IDisposable perhaps?

Dave Sexton
  • 2,562
  • 1
  • 17
  • 26
0

you mentioned 'scala' in your tags, so: on jvm it can be done as a soft/weak reference. you can port that concept to different technology but will have to do memory management yourself. but it better fits to handling single values rather than streams

piotrek
  • 13,982
  • 13
  • 79
  • 165
  • 1
    A weak reference is nota promise inverse though. What he wants is a value (let's call it Expirable) that you can unwrap it like a Scala Future, and that works if you append handlers quick enough, at one point the value can "expire" at which point you all future unwrap attempts will pend forever. – Benjamin Gruenbaum Sep 29 '14 at 07:43