From: Walter Bright on 5 Dec 2006 01:11 David Abrahams wrote: > When I make that claim about C++ I am never thinking specifically > about references through invalid pointers, because that basically > never happens to me anymore. They rarely happen to me anymore, either, but that is not necessarily because C++ has gotten better. It's just that, over the many years, I've sort of built up patterns of thought and practice that protect against them. It's like wandering through your house at night with the lights off. You eventually learn where the stairs and coffee table are and remember not to fall down them or bark your shins <g>. But it's unreasonable to expect that level of expertise in general. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Andrei Alexandrescu (See Website For Email) on 5 Dec 2006 01:21 David Abrahams wrote: > I guess so. We were talking more generally about using a pointer to > an object that another part of your program thought it had torn down > or caused to disappear. In C++ that translates into arbitrary memory > overwrites which can sometimes be detected by the OS or an external > tool; in Java that translates into the use of a zombie object, which > can never be detected except maybe by the addition of handwritten > asserts to your code. Which is an important thing! I'm not sure I understand the point. Do you call a "zombie object" something like, e.g., a closed file? In that case, isn't it a good thing that that file's write method can check that the file is still open? And isn't it comforting to know that the file could only have been closed by actual legal code? I mean, these zombie objects are not just appearing in the program nilly-willy, they are the result of the runtime deterministically executing code as instructed by code. No? So then what would there be to complain about? >>>>The memory-safe program wins because it never overwrites arbitrary >>>>memory; so all objects unaffected by a bug respect their invariants. >>> >>>The same is trivially true of C++: all objects unaffected by a bug >>>respect their invariants. >> >>This is wrong. > > > How can it possibly be wrong? I don't care about a set that I know exists but I can't define. > I understand that if you believe certain "sealed" subsystems (like a > logging module) are themselves bug-free then you don't need to look at > them for the cause of your bug... but then you wouldn't look to such a > system in a C++ program either, even if it *can* get stomped by > erroneous code. > > I guess I just don't see any black-and-white difference here. Can you > help me understand how this advantage plays out in practice? I don't think I can give it a better shot, partly because I can't dedicate enough time to it, partly because I can't explain it well, and partly because the whole issue is not as black and white as you might think I believe it is. It's not that someone can sit down with pen and paper and prove formally something of this kind. Andrei -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Andrei Alexandrescu (See Website For Email) on 5 Dec 2006 01:22 David Abrahams wrote: > "Andrei Alexandrescu (See Website For Email)" >>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. Once you discover something is wrong you > have no way of knowing where the code causing the wrongness was or > what the wrongness has affected [see below]. > > When I make that claim about C++ I am never thinking specifically > about references through invalid pointers, because that basically > never happens to me anymore. I'm just thinking about what happens to > the program state. Well if we consider C++ code that never references the wrong memory, the differences from Java narrow considerably, and whatever arguments I can bring in the discussion narrows considerably. > One way to think of this is that if you imagine the use of > FORTRAN-style data structures with indexing instead of pointers (and > actually I think in some sense you need these in Java because there's > no pointer arithmetic), even integers can "dangle." Just shorten an > array and there you are. So I don't think there's anything intrinsic > in keeping pointers valid (even if valid only means pointing to an > object that should really be gone) that limits the spread of broken > invariants. There is something intrinsic. The off-bounds integer can be easily caught; the dangling pointer can't (unless it's implemented otherwise than a memory address, which I don't see as interesting). > However, I doubt the practicality of writing whole systems that way. > 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. I don't understand this part. Basically if you have memory safety it's possible with language-provided encapsulation to define a type that is able to preserve its own invariant. No? I don't see the hell breaking loose. It's holding tight :o). >>>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 :) It's not synchronized via a lock; it's just guaranteed to be an atomic write. I think that's an important guarantee - it's one of the guarantees that allows memory safety. >>Than "all the hell breaks loose starting at this point". > > > Oh, but that's not guaranteed either. If you're going to compare > value, you should compare the Java guarantee against: > > * better speed > * the flexibility to respond to errors in special ways > * (I had another but then it flitted away) > > Anyway, I'm not claiming to know what's more valuable in the long run, > I'm just challenging what I think are some of the usual assumptions > around this question, one of goes something like, "undefined behavior > in a language has no merits." Never claimed that. Features with undefined behavior confer efficiency and expressiveness to programs. The art is finding ways to preserve as much as possible the speed and the expressiveness, while statically disallowing programs that aren't correct. Andrei -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Walter Bright on 5 Dec 2006 06:05 David Abrahams wrote: > I understand that if you believe certain "sealed" subsystems (like a > logging module) are themselves bug-free then you don't need to look at > them for the cause of your bug... but then you wouldn't look to such a > system in a C++ program either, even if it *can* get stomped by > erroneous code. > > I guess I just don't see any black-and-white difference here. Can you > help me understand how this advantage plays out in practice? Let's suppose you discover that one of your objects of type X has an erroneous value in one of its members. With a language that guarantees that only references to X can ever modify a member of X, you only need to look at references to X to find (at least the next step) in solving the problem. With C++, which can easily have pointer bugs, it could be any code in the whole program which might be the source of the problem. More things to check means it takes longer and is harder to track down the problem. -- [ 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:09
Andrei Alexandrescu (See Website For Email) wrote: > James Kanze wrote: > > Andrei Alexandrescu (See Website For Email) wrote: > >> David Abrahams wrote: > >>> 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. > > For a particular definition of "invalid". As Jean-Marc pointed > > out, you can very easily end up with pointers to invalid > > objects. > I said "invalid pointer", not "pointer to invalid object". > "Invalid pointer" = typed pointer pointing to a region of memory that > the program does not assume is of that type. I'm having trouble parsing that last statement. Be it Java or C++, you can end up with a pointer to a destructed object. Raw memory, in sum. In C++, that's called an invalid pointer. In C++, of course, there are also other ways of getting invalid pointers---just forget to initialize one, for example, and the problem is made worse by the fact that the system may reuse that raw memory for some other object, perhaps of a completely different type. But in the end, saying that a pointer is valid when it points to an object that has ceased to live, and is no longer usable is just playing word games. > > I think you and I basically agree here (based at least partially > > on earlier discussions concerning garbage collection). There is > > an enhanced degree of safety in Java in this regard. But I > > don't like statements like "there is no invalid reference" or > > "you cannot leak memory" (which one often hears)---they give a > > false sense of security. > I can't help it. As far as I know there is no invalid reference, but > there are ways to leak memory. Whether they exist or not, I've seen both in real Java programs. > I agree there could be references to objects in states that you didn't > expect. If you consider "no longer logically existing" as a state you didn't expect. In practice, the problem is pretty much the same as that of a dangling pointer in C++: in Java, you could potentially protect against it, and detect the case (not that anyone does), where as in C++, there's a good chance of the program crashing, which you can't ignore (but it's not guaranteed, and all too often, where it crashes is far from the offending code). > > It's much easier to protect against > > accidentally using an invalid object, since the memory > > containing the object cannot be used for any other use as long > > as there is a pointer to it, but the object may still be > > invalid. > Oui. The thing is, the program invalidated the object itself with > operations defined by the object; it wasn't invalidated as result of > some unrelated invalid object. But that doesn't stop it from being undefined behavior. If I do "delete p" in C++, then use p, p wasn't invalidated as a result of some unrelated invalid object. I agree that there are a lot more ways to get undefined behavior in C++ than in Java. But some of the ways work in both languages: violating thread safety, etc. And while I don't think I'd consider using a pointer to a "disposed" object really undefined behavior in Java, the effect can often be pretty much the same. (It's not undefined behavior, IMHO, because you can establish invariants which can be checked at runtime. It's pretty much the same thing because people don't, including the people who wrote the standard libraries.) -- 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! ] |