From: David Abrahams (dave_at_[hidden])
Date: 2003-02-09 17:41:05
"William E. Kempf" <wekempf_at_[hidden]> writes:
>> I don't care if you have an "uninitialized" optional internally to the
>> future. The point is to encapsulate that mess so the user doesn't have
>> to look at it, read its documentation, etc.
> I think there's some serious misunderstanding here. I never said the user
> would use optional<> directly, I said I'd use it in the implementation of
> this "async" concept.
So, we're in violent agreement? Yes, apparently there *is* some
serious misunderstanding! When did you say you were talking about the
implementation details, and how did I miss it? I thought I've been
very clear that I was talking about high-level interface issues. Did
you miss that?
>>> I *think* I understand what you're saying. So, the interface would be
>>> more something like:
>>> future<double> f1 = thread_executor(foo, a, b, c);
>>> thread_pool pool;
>>> future<double> f2 = thread_pool_executor(pool, foo, d, e, f);
>>> double d = f1.get() + f2.get();
>>> This puts a lot more work on the creation of "executors" (they'll have
>>> to obey a more complex interface design than just "anything that can
>>> invoke a function object"), but I can see the merits. Is this
>>> actually what you had in mind?
>> Something very much along those lines. I would very much prefer to
>> access the value of the future with its operator(), because we have lots
>> of nice mechanisms that work on function-like objects; to use get you'd
>> need to go through mem_fn/bind, and according to Peter we
>> wouldn't be able to directly get such a function object from a future
> Hmmm... OK, more pieces are falling into place. I think the f() syntax
> conveys something that's not the case, but I won't argue the utility of
I understand your concern. Another possible interface that is
"functional in nature" would be:
future<double> f1 = thread_executor(foo, a, b, c);
future<double> f2 = thread_pool_executor(pool, foo, d, e, f);
double d = async_result(f1) + async_result(f2);
Where async_result would be a function object instance. That may seem
radical to you, but I think Joel has demonstrated the effectiveness of
that approach in Spirit.
>>>>> Only if you have a clearly defined "default case". Someone doing a
>>>>> lot of client/server development might argue with you about thread
>>>>> creation being a better default than RPC calling, or even
>>>>> thread_pool usage.
>>>> Yes, they certainly might. Check out the systems that have been
>>>> implemented in Erlang with great success and get back to me ;-)
>>> Taking a chapter out of Alexander's book?
>> Ooooh, touché! ;-)
>> Actually I think it's only fair to answer speculation about what
>> people will like with a reference to real, successful systems.
> I'd agree with that, but the link you gave led me down a VERY long
> research path, and I'm in a time crunch right now ;). Maybe a short code
> example or a more specific link would have helped.
Sorry, I don't have one. Oh, maybe
http://ll2.ai.mit.edu/talks/armstrong.pdf, which includes the
"fabulous 10 minute Erlang course" would help. The point is, they use
Erlang (a functional language) to build massively concurrent, threaded
systems. Erlang is running some major telephone switches in Europe.
>> I'm not yet wedded to a particular design choice, though I am getting
>> closer; I hope you don't think that's a cop-out. What I'm aiming for is
>> a particular set of design requirements:
> Not a cop-out, though I wasn't asking for a final design from you.
>> 1. Simple syntax, for some definition of "simple".
>> 2. A way, that looks like a function call, to create a future
>> 3. A way, that looks like a function call, to get the value of a future
> These requirements help me a lot. Thanks.
-- Dave Abrahams Boost Consulting www.boost-consulting.com
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk