[futures] untyped_promise or future<void>

I've started to use my futures implementation at http://braddock.com/~braddock/future in a project. I've come across a few cases where I need access to some of the promise and future members (ready(), cancel(), etc), but don't actually care about the type of the promise/future. For example, I have a scheduler, and I want to be able to call scheduler.post(f /* function */, p /* promise */) where my scheduler can then add a cancelation handler to the promise, possibly track if the future/promise has been fulfilled, cancel the promise, etc, but yet has no need to know the type of the promise (which would require a templated post() function). I solved this problem by creating an "untyped_promise" class, which is constructable from a typed promise<T>, but gives access to all methods of the same promise instance, except for set() and get() obviously. I was interested in thoughts on this untyped_promise. Looking around, I found a post by Herb Sutter to the cpp-threads list where he also considered this situation. He suggested making future<T> implicitly convertible to future<void> so that future<void> could be used for this purpose (not using a split future/promise concept). I kinda like that idea actually. Thoughts? Thanks, Braddock Gaskill Dockside Vision Inc

On Saturday 24 March 2007 09:20 am, Braddock Gaskill wrote:
I've come across a few cases where I need access to some of the promise and future members (ready(), cancel(), etc), but don't actually care about the type of the promise/future. For example, I have a scheduler, and I want to be able to call
scheduler.post(f /* function */, p /* promise */)
where my scheduler can then add a cancelation handler to the promise, possibly track if the future/promise has been fulfilled, cancel the promise, etc, but yet has no need to know the type of the promise (which would require a templated post() function).
I solved this problem by creating an "untyped_promise" class, which is constructable from a typed promise<T>, but gives access to all methods of the same promise instance, except for set() and get() obviously.
I was interested in thoughts on this untyped_promise.
Looking around, I found a post by Herb Sutter to the cpp-threads list where he also considered this situation. He suggested making future<T> implicitly convertible to future<void> so that future<void> could be used for this purpose (not using a split future/promise concept). I kinda like that idea actually. Thoughts?
Seems like a good idea to me. I didn't like it at first because I thought you were suggesting giving a new alternate meaning to future<void>, and getting its behavior confused with a smart pointer class, but really it doesn't seem to. I don't really see the point of bringing promise into this though. Is it just because your add_callback is a member of promise and not future (that's only my recollection)? In libpoet, slots can be connected to futures to observe a promise being fulfilled or reneged, and there is a future::cancel(). I seem to remember your future having a cancel too. I didn't even bother to make promises implicitly convertible between compatible template types as it all seems to be covered by implicitly convertible futures. -- Frank

On Sat, 24 Mar 2007 11:49:23 -0400, Frank Mori Hess wrote:
I don't really see the point of bringing promise into this though. Is it just because your add_callback is a member of promise and not future
Well, only a promise can set_exception(), and I could imagine wanting a scheduler to do that (f.set_exception(resource_unavailable()), etc). I also only have set_cancelation_handler() attached to promise, but that is secondary. My promises are not yet implicitly type convertible, but I planned to add that.
futures to observe a promise being fulfilled or reneged, and there is a future::cancel(). I seem to remember your future having a cancel too.
I certainly have a future::cancel(); so do Peter's C+0x proposals. I remain a little conflicted about cancel() though...first off because it brings set_cancelation_handler() into the picture, which is a complication. Secondly, because it makes future<T> into a type of "task_handle". If I have future<T>::cancel(), I start to be tempted to add future<T>::set_task_priority(), etc. cancel() weakly implies that there is one pending "task" per future, which is not necessarily true. Except for that pesky "cancelation handler" callback, a cancel() call is the same as set_exception(future_cancel()) on the promise. Thus it kind of breaks the promise/future split. Once thread_safe_signals is "out there", then I'd like to use it in place of add_callback(). Both can also be used in place of "set_cancelation_handler()", since a cancelation is basically just set_exception(future_cancel()). Peter's proposal doesn't have an add_callback(), but it does have a set_cancelation_handler(), if I recall. Braddock Gaskill Dockside Vision Inc

Braddock Gaskill wrote:
Except for that pesky "cancelation handler" callback, a cancel() call is the same as set_exception(future_cancel()) on the promise. Thus it kind of breaks the promise/future split.
In my proposed model, cancel() doesn't place an exception into the future. It's a consumer-side operation, used to indicate that the consumer is no longer interested in the outcome. set_exception( fork_canceled() ) is called by the producer if the cancel() call succeeds in canceling the task before it has finished.

On Sat, 24 Mar 2007 19:29:12 +0200, Peter Dimov wrote:
In my proposed model, cancel() doesn't place an exception into the future. It's a consumer-side operation, used to indicate that the consumer is no longer interested in the outcome. set_exception( fork_canceled() ) is called by the producer if the cancel() call succeeds in canceling the task before it has finished.
This is a better behavior - I like it. It keeps the clear separation of future/promise (consumer/producer). The consumer can "request" a cancel() through the future, but it is still up to the producer to do something about it through the promise (possibly within the cancel_handler callback if desired) or ignore it. I don't see any downside - I'll change my implementation to match. The promise/future split with reference-counted promises keeps looking better and better to me. braddock

On Saturday 24 March 2007 12:52 pm, Braddock Gaskill wrote:
Except for that pesky "cancelation handler" callback, a cancel() call is the same as set_exception(future_cancel()) on the promise. Thus it kind of breaks the promise/future split.
I had similar misgivings about future::cancel() when splitting promise out of future, as mine works similarly. I suppressed those doubts at the time, because the alternative I saw of just having it reduce a reference count in the promise would require the future's destructor to do a cancel() to be at all useful. That causes problems for me, because I don't want method requests to be cancelled just because the returned future was ignored and went out of scope.
Once thread_safe_signals is "out there", then I'd like to use it in place of add_callback(). Both can also be used in place of "set_cancelation_handler()", since a cancelation is basically just set_exception(future_cancel()).
It is out there: http://www.comedi.org/projects/thread_safe_signals/doxygen/index.html Unless by "out there" you mean accepted into boost, which would also be a reasonable definition. -- Frank

On Sat, 24 Mar 2007 16:42:36 -0400, Frank Mori Hess wrote:
count in the promise would require the future's destructor to do a cancel() to be at all useful. That causes problems for me, because I don't want method requests to be cancelled just because the returned future was ignored and went out of scope.
Yes, I considered the same last-future-out-of-scope-cancels behavior, and also decided against it for the same reason. Also, since any existing promise can be used to obtain more future's, having no future instances for a given promise does not necessarily mean there won't be future instances later. Independent validation is nice, I'm glad we're working in the same space. -braddock
participants (3)
-
Braddock Gaskill
-
Frank Mori Hess
-
Peter Dimov