Putting the auto-join on the attend side seems to make it difficult to
implement IDeref and IPending. If the join were implemented by an
executor-like, you could opt out on attend by passing nil for the
executor. But there is no way to opt out for deref or realized?, other
than binding some dynamic variable.
I still can't think of any use cases for hooking into the join for
cljque's Promise. If someone needs to do something different, they
should probably implement a new promise type, instead of trying to
shove it inside some Executor notion. I wonder, then, if the join
should be done inside Promise's -deliver, rather than in the deliver
helper, so that other promise types can customize their join if
necessary.
It could be nice if then and recover returned a promise of the same
type as the source. Otherwise we wind up with Promise everywhere and
it becomes harder to work with certain custom promise types. A
protocol similar to IEmptyableCollection might allow creating an
unrealized promise of the same type as another promise, say
(defprotocol IEmptyablePromise (empty-promise [this])). It could work
to assume that the return value is both INotify and IDeliver.
Personally I tend to prefer to separate the IDeliver and INotify
implementations (though "we're all consenting adults" is almost
convincing to me). If IDeliver had an extra function, say (notifier
[this]), which returned an INotify (and was the identity on Promise),
then empty-promise could just return an IDeliver. then-call could then
look like:
https://www.refheap.com/paste/43f1c7f13480a4f025bda6dd7 .