Guido van Rossum wrote:
Futures or callbacks, that's the question...
I know the C++ standards committee is looking at the same thing right now, and they're probably going to provide both: futures for those who prefer them (which is basically how the code looks) and callbacks for when every cycle is critical or if the developer prefers them. C++ has the advantage that futures can often be optimized out, so implementing a Future-based wrapper around a callback-based function is very cheap, but the two-level API will probably happen.
Richard and I have even been considering APIs like this:
res = obj.some_call(<args>) if isinstance(res, Future): res = yield res
or
res = obj.some_call(<args>) if res is None: res = yield <magic>
where <magic> is some call on the scheduler/eventloop/proactor that pulls the future out of a hat.
The idea of the first version is simply to avoid the Future when the result happens to be immediately ready (e.g. when calling readline() on some buffering stream, most of the time the next line is already in the buffer); the point of the second version is that "res is None" is way faster than "isinstance(res, Future)" -- however the magic is a little awkward.
The debate is still open.
How about: value, future = obj.some_call(...) if value is None: value = yield future Or: future = obj.some_call(...) if future.done(): value = future.result() else: value = yield future I like the second one because it doesn't require the methods to do anything special to support always yielding vs. only yielding futures that aren't ready - the caller gets to decide how performant they want to be. (I would also like to see Future['s base class] be implemented in C and possibly even preallocated to reduce overhead. 'done()' could also be an attribute rather than a method, though that would break the existing Future class.) Cheers, Steve