
Important confession since Fergus is in the discussion: I've not actually read any of the C or C++ standards; I've got an impression of what they say from various textbooks and the gcc mailing lists. On Fri, 27 Jul 2001, Fergus Henderson wrote:
But there are so *many* such "stupidities".
If you took out all of the things in C that had implementation-defined, unspecified, or undefined behaviour, then what you'd be left with wouldn't be C.
If you were talking about some other C-like language, such as LP-C, Java, or C#, then I think your point might be valid. But the differences between C and higher-level imperative (or OOP) languages should not be ignored.
I'm sure you're right. However, this seems to fit paradoxically with my personal experience, and that of the people that I discuss this stuff with at work. This may be something to do with the fact that we're developing programs of the scientific kind (e.g., image segmentation) and that virtually everyone tends to unconsciously follow the KISS (Keep it simple, stupid) principle: our goal is very much to produce programs that `do cool things' rather than `are cool due to the way they are coded'. And I _still_ don't think that there are that many bugs that hit me due to implementation definedness or weird corner-cases in the syntax. If you had a time machine, took a piece of code that I'll write in the future with a bug in it and asked me to figure out what the bug in there was I bet that, in most cases given just enough time, patience, paper and coffee I could find the bug without a computer and it wouldn't be involve the compiler defining something one way whereas I thought the standard defined it another. I generally don't produce programs with bugs because the compiler implements some particular construct differently to the way that I think it sould but because I can't keep the whole program and the interactions between all its parts straight in my very limited mind. (I feel like a bee-keeper at apocryphal dinner party where it's said that by the laws of physics bees can't fly: all the other parties in this discussion are much more technically competent and well-read than me and yet my actual experiences don't seem to accord with their conclusions :-) )
Likewise, C and C++ have specifications which are met to a reasonable degree by many compilers out there, which prompts the question: when was the last time a bug in your code in an imperative language was due to an implmentation-defined part of the language? In 5 years of intensive C++ programming I'd guess I've made maybe 25 bugs due to this, but the number of bugs I've fixed in my code must be in the tens of thousands.
If you also include areas which are unspecified or undefined, as well as those that are implementation-defined, I think it would cover a very substantial proportion of those tens of thousands of bugs.
How many times have you written code that accidentally referenced an uninitialized variable, for example? Or that accessed memory after it had already been deallocated? Or that tried to access past array bounds? These are very common kinds of errors.
I haven't been very precise in my terminology (and as I say haven't actually read the standards). When I talk about something being implementation defined I mean that the precise details of how it is defined in an implementation needs to be understood for a `bug-free' program to work. I've been calling a statement (which I'm not claiming to have read verbatim anywhere) like `accessing memory outside allocated array bounds can non-determinisitically corrupt any part of the overall state of the program, return correct or gibberish results or cause the program to abort' to be perfectly reasonable defined statement of what to expect. It can certainly be viewed as either `under'-defined, or that what actually happens to be implementation defined. But I don't consider that when I screw up by allocating memory outside array bounds to be a bug due to implementation-definedness, it's a bug because I didn't spot some interaction that caused the variable that I was accessing the array at to become a value that was to big. But to some extent I've been arguing about C just because I think I'm right rather than because I think it's important to considering the overall question. Suppose that I'm working in Java. I'm told that if an access is made to a index outside the range of an array it throws an exception. How would you classify the following situation: * within some routine f: * a variable v is set up which holds the (valid) index at which I want to access the array at the start of the routine. * somewhere deep in a lot of code something ERRONEOUSLY assigns a value to that variable v which is outside the range of the array. * a read of the array at index v is attempted. An exception is thrown. * an catch block governing f catches the exception and prints out `Attempt to access array outside its range.' Nothing here is talking about unspecified semantics, or implementation definedness. Has the actual problem which is causing my program to not be useable for its intended purpose (`the bug') gone away? Is the bug fundamentally different to what it would be in a C implementation? If you were asked what the cause of the bug was, would you say that it was anything other than the erroneous assignment to v? Basically my argument was that in an imperative language the semantics do not generally cause the problem of figuring out why v has the wrong value (or equivalently, being sure when I wrote the code that v has the correct value) to fall apart into sufficiently small problems that effective reasoning becomes possible. On the other hand I believe the semantics of functional languages _do_ have this `meta-property'. ___cheers,_dave________________________________________________________ www.cs.bris.ac.uk/~tweed/pi.htm |tweed's law: however many computers email: tweed@cs.bris.ac.uk | you have, half your time is spent work tel: (0117) 954-5250 | waiting for compilations to finish.