From: Peter Dimov (pdimov_at_[hidden])
Date: 2001-09-24 05:57:09
From: "David Abrahams" <david.abrahams_at_[hidden]>
> From: "Peter Dimov" <pdimov_at_[hidden]>
> > The point is that overloading a name to mean different things in
> > contexts is not necessarily a good thing. An overloaded name implies
> > don't care about the specifics of the call. I simply say x + y and
> > to do the right thing. Obviously, when I say wait(x) I do care about
> > 'wait' variation is being performed.
> Just as when you do std::cout << x you care about which streaming
> is being performed... but there is a single way to stream that's
> for each type you can use for x. Trying to remember a separate name for
> of the streaming operations just makes life harder.
No, I don't care about which streaming operation is being performed. That's
what makes writing templates like lexical_cast<> possible.
The Dimov Test for Appropriate Overloading (DTAO) ;-) is "can you answer the
template<class T> void f(T & t, U & u)
std::cout << t; // what does this line do?
wait(t); // ditto
wait(t, u); // ditto
Aside: another application of the same rule:
template<class Lock, class Mutex> void f(Mutex & m)
Lock l(m); // what does this line do?
> > The 'join' variation invalidates x;
> I think seeing it that way requires a kind of "manufactured ignorance"
> there is any threading. Join actually /waits/ for x to become invalid.
This is what I'd like it to do, but it's not what it presently does.
t.join() really does invalidate t, it doesn't wait and observe. Example:
t.join(); // undefined behavior
sleep(...); // t ends in the meantime
t.join(); // well defined behavior
> > I can't simply say wait(t) inside and trust it to perform the right kind
> > operation. I have to know what t is, and if I do know that, why define
> > function as a template?
> Precisely. And how would having different names help with this situation?
Why should they help with it? What is the problem that you're trying to
> > (The Win32 API is a good example of why this kind of wait() overloading
> > doesn't really work.)
> Details, please.
"The WaitForSingleObject function can wait for the following objects:
The problem with this overloading is that given a generic HANDLE, you
shouldn't even think about Wait'ing on it; the Wait operation could acquire
the mutex, or have some other unexpected side effect.
The common name implies common semantics, which is not the case here. This
is lying to the user. The user will exact revenge. ;-)
> > Now if you refine the wait() semantics a little, saying that wait(e)
> > the current thread until the event e occurs, and then provide a way to
> > specify a 'thread finished' event, a 'time reached' event, a 'predicate
> > true' event, I'll be inclined to agree with you.
> How does the above differ substantially from what we'd get if we just gave
> the current wait/sleep/join semantics the same name?
Here's a sketch:
Effects: blocks the current thread until the event e occurs.
Effects: blocks the current thread until the event e occurs or the time xt
is reached, whatever happens first.
Returns: true if e has occured, false otherwise.
Now we need to define what 'event' means:
Do the above operations invalidate e? Change e?
Can I wait() several times in a row on the same event?
Is an Event CopyConstructible? Assignable? EqualityComparable?
Is an Event a compile-time concept or a run-time concept?
If the latter, are all Events derived from a common AbstractEvent? Or is an
Event a handle to an AbstractEvent body?
Is a thread an event? Should it be?
Is an xtime an event? Should it be?
How can I convert a (condition&, predicate, mutex&) tuple to obtain an
And several others that I'm sure somebody will come up with.
What I'm trying to say is that designing an uniform 'wait' layer is a
serious task, and simply adding three wait overloads is unlikely to achieve
Another perspective: we have three categories of users:
1. Threading experts;
2. Pthread programmers;
3. Programmers with little or no thread experience.
The problem we're trying to solve, AFAICS, is that the current design does
not target (3). The proposed solutions so far concentrate on renaming
functions. Does this help?
Not much, I'd say. We need another, higher level, abstraction layer that is
specifically designed with (3) in mind. Let's leave the current low-level
design suitable for (1) and (2). Using standard POSIX names (and semantics)
is such a step.
-- Peter Dimov Multi Media Ltd.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk