Re: The D Programming Language
Andrei Alexandrescu (See Website For Email) wrote:
Andrei Alexandrescu (See Website For Email) wrote:
James Kanze wrote:
Andrei Alexandrescu (See Website For Email) wrote:
That's simply wrong. Java does not check thread safety
statically, yet is able to define behavior of even incorrect
multithreaded code.
Writing to a double while another thread is reading it is
undefined behavior in Java.
I've ran a number of searches for that ("java undefined behavior
double", "java undefined behavior threads double" etc.), no avail. I'd
be glad if you provided a reference. Thanks!
Maybe (also) we're using slightly different definitions for undefined
behavior?
I am still waiting for a response on this issue, or a retraction of the
initial statement.
Sorry, I missed your previous posting. (I've not been following
this thread too closely, since D is not a topic which interests
me much.)
I don't know quite what different definitions we could be using.
Undefined behavior occurs when the language specification places
no definition on the behavior. I don't know how you can easily
search for it, because it is the absence of a definition. Java
(and most other languages) don't use the term, or even specify
explicitely what they don't specify. So the reponse is rather
the opposite: unless you can find some statement in the language
specification which defines this behavior, it is undefined
behavior.
Actually, I think there are even more cases, involving multiple
writes to different variables. But the case of double or long
is flagrant, since the language specification does not require
the writes to be atomic.
In practice, of course, Java runs on hardware, and it is always
tributary to what the hardware does. And the hardware itself
has undefined behavior when there are multiple writes and reads
from different threads, with no intervening fence or membar or
whatever instructions. Putting such instructions around each
and every access would slow the machine down too much, so they
accept undefined behavior.
This is relevant to C++ in the following way. When the C++ thread
standardization process started, it was assumed that the Java memory
model ensures well-defined programs even when they do have races. The
committee decided (correctly IMHO) to depart from that model for
efficiency reasons, leaving the behavior of certain programs undefined.
My current understanding is that races on longs and doubles could
produce undefined longs and doubles being read, but not undefined programs.
What's the difference? Especially in the case of double, where
the undefined double might be a signaling NaN?
In practice, the intent is clearly to allow reads and writes to
occur without intervening synchronization. And the hardware
offers very few guarantees in such cases.
Now, if Java does allow programs with undefined behavior, that would
quite change the "golden standards" in terms of safety.
Well, there's a certain sense in which all languages have
"undefined behavior". The C standard (and I think C++) speak of
undefined behavior if the program exceeds the resource limits.
One generally thinks of this in terms of memory, or stack
overflow, or such, and Java does define behavior in such cases.
But on the machines I use, there are other essential
resources---most of the chips require 5 volts, -/- 10%, or
something like that. If the power supply voltage drops, they
start behaving in a random fashion. Insufficient voltage (a
resource) results in undefined behavior, and there's nothing the
language specification can do to change it.
Obviously, I don't think it's quite the sort of thing we have in
mind in general. But I mention it to relativize the importance
of no undefined behavior. Gratious undefined behavior (e.g.
that due to modifying the same variable twice without an
intervening sequence point) is just plain stupid---there's no
excuse for it. IMHO, Java does an excellent job in this
respect, and is a good model for this type of undefined
behavior. And C++ is a disaster in this regard, and seriously
needs improvement. Intentional undefined behavior, such as that
resulting from the use of reinterpret_cast, is necessary if you
want to support low level programming---there's no point in
comparing C++ with Java here, because Java intentionally
excludes these types of applications. Finally, there is
undefined behavior simply because current hardware doesn't
permit avoiding it, at least not without outrageoulys excessive
costs. You can't (reasonably) say that an implementation is not
conforming unless it has a back-up power supply, and in a
general purpose language, you cannot reasonably require defined
behavior if two threads start modifying the same variable at the
same time.
At any rate, I think any discussion concerning undefined
behavior is rather senseless unless it keeps these distinctions
in mind. I'm rather glad that C++ has the undefined behavior
which results from abusing a reinterpret_cast; it's useful, even
necessary for certain types of applications, and
reinterpret_cast is easily grepped for, so I can avoid it
(provided the compiler complains when a C style cast or a
function style cast resolves to a reinterpret_cast) when it's
not necessary. And for better or for worse, I think we're stuck
with undefined behavior (at least at the program level) when
threads are involved. But I would definitly support reducing or
even completely eliminating undefined behavior of the first
sort.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient?e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S?mard, 78210 St.-Cyr-l'?cole, France, +33 (0)1 30 23 00 34
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]