From: James Kanze on
Peter Dimov wrote:

> It is certainly true that illegal operations that manifest themselves
> as changing valid object memory at a random location are an incredible
> pain to debug. On a practical level, this cannot be denied. On a
> theoretical level, there is nothing in the C++ specification that
> mandates that undefined behavior must be left undetected; in principle,
> this allows a C++ implementation to be safer than Java. (In practice,
> this never happens, because there is (was?) no market demand for it.

Are you sure? What about CenterLine? What about running C++
under Purify?

Given the widespread use of Purify (and valgrind, and other such
tools), I'd say that there definitly is a market demand for such
verifications, and it's being met. The difference with regards
to Java, here, is that the design of Java allows such run-time
checks to be cheap enough that they can remain in the delivered
code. (The language specification says that they have to, but
we all know what that's worth. If they weren't cheap enough,
every JVM would have an option to turn them off, language
specification or no.)

--
James Kanze (GABI Software) email:james.kanze(a)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! ]

From: James Kanze on
David Abrahams wrote:
> "Andrei Alexandrescu (See Website For Email)"
> <SeeWebsiteForEmail(a)erdani.org> writes:

> > David Abrahams wrote:
> >> "Andrei Alexandrescu (See Website For Email)"
> >>>>That said, even in a system with no undefined behavior, we have no
> >>>>idea what the value of x (or anything else in our program) is after a
> >>>>programming error, so the ability to continue on with the program
> >>>>executing the instructions you thought you were giving it originally
> >>>>is not as valuable as it might at first seem.

> >>>It's not "anything else in our program". It's "anything else in our
> >>>program that was affected by x"

> >> No, not at all. Re-read the scenario; "x" didn't necessarily have
> >> anything to do with the programming error. From a practical point of
> >> view, by the time your internal checks/assertions have detected that
> >> there's been a programming error by inspecting some piece of program
> >> state (call it Z), you have no idea how far the damage has spread.
> >> That is, the program's own guarantees are out the window.

> > I disagree. As I explained before: in Java bugs can be made modular in
> > ways that are not possible in C++, because you have true memory
> > isolation between objects.

> True memory isolation is very nice, but I don't see how it helps make
> bugs modular in practice.

Sure it helps. A lot, even, if you want it to. But it isn't a
panacea, or a silver bullet. It's just one more tool. It can
reduce the number of places where you have to look, even if it
won't tell you exactly what's wrong.

Why all the extremist positions? You're saying it won't help;
Andrei says it eliminates all forms of undefined behavior.
Personally, I think it helps a lot, but there are problems it
doesn't solve, and there are other forms of undefined behavior
which have to be dealt with, at least in real programs running
on real machines.

In the end, I find it easier to write robust code in C++ than in
Java, but it's despite the way pointers work in C++, not because
of it.

[...]
> [below] Okay, I suppose it's possible to write subsystems that make
> absolutely no assumptions about what their clients pass other than
> what's guaranteed by the type system, and if those subsystems have no
> bugs, you know these subsystems still intact -- a valuable property
> for diagnostic subsystems like loggers.

> However, I doubt the practicality of writing whole systems that way.

The problem isn't the practicality of your writing a whole
system this way. The problem is that you will be using
libraries that you don't write that weren't written this way.
And also...

> Eventually you'll end up with functions that require a certain
> relationship between parameters (e.g. end >= begin), and then to
> maintain the "no assumptions about the inputs" stance you have to
> check these relationships, and throwing an exception becomes part of
> the function's defined behavior. Since the function calling with
> arguments (end < begin) is already holding broken data or broken
> assumptions, all hell then breaks loose.

One of Java's faults is that it doesn't allow you to do anything
reasonable (like crashing) when you've detected the problem.
All you can do is log the error and throw an exception, hoping
that 1) nobody silently swallows the exception (except that
major standard library components do silently swallow
exceptions), and 2) someone reads the log, and notices what went
wrong.

(Actually, part of this is related to mentality. At least under
Unix, you can set SIGSEGV to SIG_IGN, and carry on. But nobody
does this, whereas, As I said, major standard library components
in Java silently gobble up exceptions.)

> >> Meaning that in Java, all writes of "references" (a.k.a. pointers) are
> >> synchronized?

> > That is correct. They are guaranteed to be atomic; there is no invalid
> > reference in Java, ever, period.

> Wow; that does sound slow :)

I get the feeling that Andrei is confusing atomic and
synchronized. Writes to pointers in Java are guaranteed to be
atomic; they're not "synchronized", neither in the usual sense,
nor in the Java language sense.

Of course, this means that other threads can see pointers to
objects which aren't yet constructed. But that's generally true
in Java, even without threads; just call a virtual function from
a base class constructor. Worse, other threads can see pointers
to objects which haven't yet been zero initialized (or
initialized at all). That is, of course, the undefined behavior
that Java supposedly doesn't have. (I'm rather surprised that
Andrei doesn't recognize this. IIRC, he's written on the
problems of double checked locking in the past, and this problem
is related.)

--
James Kanze (GABI Software) email:james.kanze(a)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! ]

From: James Kanze on
Walter Bright wrote:
> Al wrote:
> > I'm kind of curious about the inline keyword. If the compiler is allowed
> > to:

> > a) Ignore it when it appears (i.e. not inline).
> > b) Ignore its omission when it doesn't appear (i.e. force inline).

> > Then what exactly is the point of it? Why not just let the compiler deal
> > entirely with the efficiency of inlining by itself? Clearly, from the
> > points above, the programmer has zero control over what actual inlining
> > goes on, so why pretend that they do via a bogus keyword? It seems like
> > it just needlessly complicates the function specifier set.

> I figure the 'inline' keyword is just like the anachronistic 'register'
> keyword. It's unnecessary, and can even be counterproductive, with
> modern compilers.

With some modern compilers. It's still a useful optimization
tool with the most widely used compilers.

--
James Kanze (GABI Software) email:james.kanze(a)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! ]

From: Al on
Hi,

James Kanze wrote:
<snip>
> One of Java's faults is that it doesn't allow you to do anything
> reasonable (like crashing) when you've detected the problem.
> All you can do is log the error and throw an exception, hoping
> that 1) nobody silently swallows the exception (except that
> major standard library components do silently swallow
> exceptions), and 2) someone reads the log, and notices what went
> wrong.

That's an interesting problem that honestly I hadn't considered. I guess
it is kind of creepy to know that whoever is calling you might basically
ignore whatever errors you pop up.

On the other hand, from the other point of view (the caller) that's
exactly what is required. It's the very basis of exception safety.

Look instead at C++'s throw(). Seems completely bogus to me. Why?
Because in truth, it guarantees absolutely nothing, unlike Java.

Moreover, I'm not terribly familiar with the Java APIs, but from a quick
search, this showed up:

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/System.html

Of note is:

static public void System.exit(int);

Which seems to do exactly what you want (i.e., elevate the error all the
way up the hierarchy to make sure it gets paid attention). What more do
you want?

> (Actually, part of this is related to mentality. At least under
> Unix, you can set SIGSEGV to SIG_IGN, and carry on. But nobody
> does this, whereas, As I said, major standard library components
> in Java silently gobble up exceptions.)

Cheers,
-Al.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Jean-Marc Bourguet on
"Andrei Alexandrescu (See Website For Email)"
<SeeWebsiteForEmail(a)erdani.org> writes:

> David Abrahams wrote:
> > Jean-Marc Bourguet <jm(a)bourguet.org> writes:
> >>"Andrei Alexandrescu (See Website For Email)"
> >><SeeWebsiteForEmail(a)erdani.org> writes:
> >>
> >>
> >>>Well the only thing I can add is that in my limited experience,
> >>>debugging Java programs is much easier because there's never the case
> >>>that a dangling pointer misteriously overwrites some object it wasn't
> >>>supposed to.
> >>
> >>Instead you are writing to an object which was supposed to be out of
> >>existence for a long time. In my experience, that give you the same kind
> >>of elusive bugs. Excepted that purify can't help you
> >
> >
> > I want to emphasize that point: when nothing is truly illegal (like
> > those things that C++ says cause undefined behavior), there's no way a
> > tool like Purify can tell you that the program did something wrong.
>
> But in a memory-safe program you don't even need Purify to tell you that
> the program did something wrong. A logging module would suffice, and the
> proof is in the trace.

The problem is knowing what to log so that you don't have a trace with the
proof you are searching which is to big to be usefull. Purify gives me an
hint about that. In memory safe languages, I don't know where to start, or
more precisely, I've to start far further. With the run-time of the
program I'm working on, that's a major advantage.

> The important tidbit that makes it all work is that bugs anywhere in the
> program can't mess the logging subsystem.
>
> Let's face it. Memory safety is too nice a property. If the argument is
> that it leads to messier languages and slower programs, I'd agree. But
> IMHO the arguments brought in this thread didn't carry much weight.
>
> So my answer to "Purify can't tell you..." is "Because you don't need
> Purify".

I don't agree. In C++, you are able to express some of your design
assumptions about the life time of your objets (this is an automatic
objects, this object should now no more be accessed). As provided, C++ has
a limited set of such policies (static objects, automatic objects, raw
pointers, reference, smart_ptr) and has a mecanism (smart pointers) to
provide others. In some case, we have enforced sematic with it, in other
no (some people use references as soon at it can never be NULL in a correct
program, other have different rules; I've seen smart pointers introduced
just as a way to document the policy). purify allows to (partially) check
some part of the policies where it can't be checked statically.

This is quite a similar issue as typing. One can see typing systems as
introducing constraints on values. One way to classify typing system
(there are others) is untyped, staticaly typed and dynamically typed.
Untyped is unsafe because there are expressed constraints which are not
checked. Dynamically typed is safe but can't express constraints.
Statically typed is safe and can express and check constraints
(statically). Even if you don't need to express the constraints to be
safe, expressing and checking them is nice as bugs are detected earlier.

For memory management, we seem to have unsafe languages which are able to
express constraints but not to check those which are dynamic in nature --
we can force the others in the typing system -- and safe languages which
are unable to express the constraints. I'd like a language which is able
to express the constraints and runtime check those which are dynamic in
nature. C++ with purify seems nearer to that goal than the memory safe
languages I know. Ada with purify is perhaps even nearer as its typing
system is more aware of the issue.

If I was trying to do research on programming languages, that's the issue
I'd want to tackle as it is the most important issue about programming
which seems orphan from my perspective.

Yours,

--
Jean-Marc

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]