From: James Kanze on 5 Dec 2006 06:15 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 5 Dec 2006 06:14 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 5 Dec 2006 08:49 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 5 Dec 2006 11:30 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 5 Dec 2006 11:32
"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! ] |