Talk:Criticism of the C programming language

From Wikipedia, the free encyclopedia

Contents

[edit] Restoring Neutral Point Of View

Some of the additions were more carping about C than factual. For example, there are solid reasons why we don't want truncated source files to go undetected, and no compelling reason I have ever heard to the contrary; further, most well-defined programming languages have a similar requirement, so even if you don't like the property it is not really a criticism of C. This article was split off the main C programming language article for structural reasons, not to provide a forum for airing grievances about C. I made some changes to restore balance. — DAGwyn 06:24, 1 September 2006 (UTC)

It still has POV problems, especially "Memory Allocation". It's unfair to just remove the section (because Memory Allocation _is_ often criticized), but these points don't apply- for example, operating system kernels don't often use heaps (and have no malloc() or similar function). It's for this reason that operating systems, and many embedded targets simply cannot be written in languages that perform automatic garbage collection or RAII. 216.169.144.254 14:56, 26 October 2006 (UTC)

If it often is a point of criticism, then it seems appropriate for this article, whether or not it is always justified. Indeed, I could "rebut" several of the criticisms, but haven't tried to do so, because that would turn the article into a flame war. — DAGwyn 21:05, 27 October 2006 (UTC)

[edit] Move?

Is there a specific reason behind this article's title? If not, I think a better name would be Criticism of C programming language. --Gray Porpoise 17:52, 4 September 2006 (UTC)

It was spun off from the main article "C programming language". As a subtopic the title seems okay to me. — DAGwyn 01:24, 5 September 2006 (UTC)
Note that it has now been renamed to "Criticism of C". — DAGwyn 19:16, 29 September 2006 (UTC)
Note that somebody has renamed it yet again, to "Criticism of the C programming language". — DAGwyn 20:37, 20 November 2006 (UTC)

[edit] Use of Integers as Booleans

The article says nothing of the use of integers as boolean values.

Is that a criticism or just a feature? Note that Knuth's book "Concrete Mathematics" made heavy use of an analogous mathematical construct. — DAGwyn 20:59, 21 November 2006 (UTC)

[edit] Call-by-reference

Isn't the complete lack of call-by-reference one of the greatest ahortcomings of C? After all, it makes programs slower (as additional checks for NULL-pointers have to be included) and and tends to introduce errors in the source (if these checks have been omitted).

Especially since call-by-reference was already present in Pascal (and probably other languages as well) which is slightly older.

C's explicit use of pointers to obtain references was a simplifying concept. C++ added reference parameters, but it needed to do that to support certain operators on classes. Checks for null pointers is a red herring, as the reference-parameter equivalent would be something like a nonexistent argument (probably not even expressible); properly programmed pointer arguments usually don't need to be checked, and in other instances it is actually useful to have an in-band special signal available.
Actually Pascal and C were developed contemporaneously.
Fortran passed parameters by reference, which in some early implementations led to errors of its own kind:


 PROGRAM MAIN
 CALL SUB(2)
 I = 2
 PRINT ' I5', I
 END
 SUBROUTINE SUB(K)
 K=0
 RETURN
 END
or something like that, which could print "0" instead of the expected "2". Anyway, if there is a significant need for pass-by-reference that C cannot meet using pointer parameters, that could be a valid criticism, but the mere fact of being different from other PLs isn't a valid criticism.
Well, you kind of got my point: In languages with call-by-reference, it is simply impossible to pass NULL, therefore no checks are necessary.
But I cannot agree with your argument regarding the Fortran example -- as parameters are always c-b-r (in this specific implemtation), one should indeed expect K=0. --MushroomCloud 00:23, 8 December 2006 (UTC)
For the record, the FORTRAN standard doesn't require call-by-reference. It specifies the behaviour (and it is a behaviour that lends itself to reference passing), but not the mechanism. One could write a standard compliant Fortran compiler that did copy-in-copy-out. -- GWO
As I said, it was a problem in some early implementations of FORTRAN, before there was even an ANSI standard for FORTRAN. The behavior illustrated by the example was actually encountered by several of us old-timers. The point of that is that pure pass-by-reference is often not what one wants either. With C, the programmer gets to choose between pass-by-value and pass-by-reference when he designs the function. — DAGwyn 22:08, 8 December 2006 (UTC).
You can du so in languages like Pascal or Ada as well, but they do so in a clean and safe way, making it impossible to pass NULL, and thereby creating safer and more efficient code. --MushroomCloud 19:56, 10 December 2006 (UTC)
I don't know why you're so hung up on passing a null pointer as argument, which can sometimes be a useful thing to allow (for example, to request use of a built-in default for that argument). As to unintended usage, C's pointers are powerful and dangerous for the same reason (namely, that the validity of pointer arithmetic relies on semantic constraints and on the pointed-to type only, not on type properties of any containing aggregate). So all sorts of erroneous usage is possible when the programmer doesn't think properly. But to some extent usage errors are possible in any language, for example accidentally interchanging the source and destination buffers for some buffer-copy function. — DAGwyn 21:16, 11 December 2006 (UTC)
I want to note also that C does not necessitate run-time checks for null-pointer parameters; indeed a C compiler cannot automatically impose that since many programs require that null-pointer arguments be allowed. I guess you must be referring to a presumed need for the programmer to perform such checks, but there is no such need in general. (It might be prudent to do so when producing a library for use by others, or perhaps as part of some overall safety strategy that to be of much use would also have to include exception handling.) A correct program does not benefit from such checks, and for incorrect programs there is no automatic way to fix them at run time. There are a variety of tools available, including checks provided by many compilers, that can detect a wide range of programming errors, more than merely having "strong typing" could catch, and it is reasonable to expect people to use them (as well as procedural approaches such as code walkthroughs). — DAGwyn 21:27, 11 December 2006 (UTC)


[edit] Undefined Behaviour section

  • Reaching the end of a function without finding a return statement, when the return value is used.

Almost any compiler less than 15 years old produces an error in this case, or at least a warning.

  • Reading the value of a variable before writing to it.

Again, most compilers raise warnings/errors about this as well.

If we're criticizing "ancient C" I suppose it's OK to leave those items in, but they are obsolete. --Shyland 11:00, 25 February 2007 (UTC)

Actually there are zillions of possible instances of undefined behavior, but the article tries to pick out several that cannot be correctly diagnosed at compile time. In fact the C standard requires conforming implementations to accept programs that potentially trigger the above cases of undefined behavior, because in general it cannot determine at compile time whether u.b. will occur at run time or not (it depends on the dynamic flow of control, which can depend on the values of variables, and on linkage to other separately compiled modules that in general are not known when compiling the current translation unit). — DAGwyn 04:29, 26 February 2007 (UTC)

[edit] Missing Features section

Come on, this whole list of "missing features" is silly. No graphics!!?? That's absurd. Any language which supported this entire litany of "missing features" would be a completely unimplementable, totally unusable mess. I believe there was an attempt to make a language which was all things to all people: it was called Ada...

Yes, there are some valid items in that list...but you'd get a different subset depending on who you talked to. --Shyland 11:14, 25 February 2007 (UTC)

The article documents common criticisms of C, and indeed one that is often heard is the lack of any standard graphics support. Java, for example, tried to address this (they didn't get it right the first time or two), and Python has a "standard" graphics interface, so it's not an entirely unreasonable thing to request. You have also mischaracterized Ada, which initially did not specify any graphics support anyway.
Note that there are "rebuttals" for many of the criticisms; it isn't the purpose of this article to debate, but rather to document. It was spun off the main C article to reduce the overall negativity of the main article. — DAGwyn 04:36, 26 February 2007 (UTC)
By the way, the language that is everything to everyone isn't called Ada, but Oz. --MushroomCloud 14:27, 26 February 2007 (UTC)

I am also amazed at what appears in the "Absent features" section. It reflects a basic misunderstanding of the purpose of C. If C was required to have garbage collection, bounds-checking, closures, etc, then it would not be possible to efficiently implement another language with C. Also, trying to write an OS kernel with a garbage-collected language is too ridiculous to even consider. Xerxesnine 21:12, 17 March 2007 (UTC)

That's not entirely true. Bounds checking is possible, in differently designed languages, without incurring much run-time overhead. So is garbage collection (via what are generally known as "on the fly" methods). Part of the perceived problem is that C has been widely used to write applications, not just "systems software". Of course these days we have Python, etc., but largely they were inspired by some of the very criticisms of C that the article documents. — DAGwyn 09:36, 18 March 2007 (UTC)
When you say "without incurring much run-time overhead", what you mean is "in many circumstances the run-time overhead of bounds-checking is negligible", which is true. But remember we must account for other circumstances. There are other cases where bounds-checking deals a significant blow to performance. These cases are non-trivial and non-rare, and for this reason C does not do bounds-checking. The same principle applies to garbage collection, dynamic stacks, etc.
You have somewhat misunderstood the point of my comment above, which is that the mere suggestion that C should incorporate these higher-level features indicates a misperception of C's niche. One part of this niche is in implementing higher-level languages. Since a higher-level language would likely do its own bounds checking (in order to throw an exception, for example), this would render C's (hypothetical) bounds-checking needless and wasteful. In many cases it would not matter, but in many cases it would.
In short, the lack of higher-level facilities like bounds-checking and garbage-collection is not a shortcoming of C. It is a feature of C. Xerxesnine 23:45, 20 March 2007 (UTC)
It is indeed possible to have compile-time bounds checking. In Ada, for example, variables can be limited to a range of values. If it is certain, that a an expression cannot be outside an array's range, the check can be made at run time. Consider:
I : Integer range 1 .. 10;
A : array (1 .. 20) of Integer;
-- ...
A (5 + I) := 1;
Here, the the expression will always be from 6 to 15, and therefore, no run-time check is necessary.
Additionally, checks may be supressed when indicated. --MushroomCloud 00:08, 21 March 2007 (UTC)
Since the purpose of Ada is nearly opposite to the purpose of C, it seems you have misunderstood my point as well. The ability to walk through raw memory is the whole point of C --- you can't build an OS kernel without that ability. You can't write an OS kernel entirely in Ada. Bounds-checking is not an "absent feature" of C. The lack of it is a feature.
Incidentally, linking to a bounds-checking library is trivial (e.g, -lefence), so the point is moot anyway. The ability to use a variety of third-party memory management libraries, rather than having the compiler imposing such management, is a feature of C as well. Low-level, complete control, wet and wild.
Don't think for a moment that I am "advocating" for C. I am merely trying to clear up what appears to be widespread misperceptions about it. Xerxesnine 01:25, 21 March 2007 (UTC)
I certainly understood the point, but keep in mind that I segregated this article from the main C article intentionally, to provide a less disruptive place to document criticisms that have some degree of validity, which may depend on point of view, purpose, etc. It isn't intended to pass judgment (except whether the criticism is reasonable enough to even mention) nor to debate within the article. In several instances, there is text that somewhat counters a criticism by explaining why things are as they are.
There are possible counterarguments to many of your arguments. For example, C could mandate bounds checking and pointer validation, but also provide an "escape" mechanism, such as "#pragma unchecked", and that would support the occasional need to violate a more restrictive model while by default imposing the model for other purposes. Much bounds checking could be performed at compile time. And C wasn't thought of as a target language until years after its invention, so those arguments don't justify the original decision.
Note that I've been using C continually since shortly after its inception, and have served on the C standards committee for decades. (We've heard a lot of criticisms of C and requests for changes! There are of course good reasons for much of the way C is specified, and the standards committee has tried to uphold them.) I'm a major proponent of C, particularly for systems work, but I also acknowledge that it has deficiencies (in some contexts), and it is worth noting them if for no other reason than to guide potential future language designers, who might be able to make better choices if they understand the consequences of past ones. — DAGwyn 20:51, 21 March 2007 (UTC)

[edit] Automatic memory management

It is said in this article that C doesn't support automatic memory management. However, such thing is not language-dependent. It is feature of supplied libraries and system environment. Now we see that .NET Framework uses automatic memory management, and native Win32 platform doesn't do it, and actually all Win32-targeted languages have not automatic memory management, but all .NET-based ones have it. Actually memory allocation and releasing is call to functions, and how these functions are implemented is not language-dependent. If we have automatic memory management library, we can call it even from Assembler.

I'd say the most important part of automatic memory management is that you shouldn't have to call any kind of delete / free function. While libraries that let you do that in C exist, they don't (and couldn't) work correctly on all C programs if you replace all calls to "malloc" with a memory manager. In languages like C# and in particular Java, you have to use the memory manager, and the standard is designed to make one easy to implement. —The preceding unsigned comment was added by Mrjeff (talkcontribs) 23:21, 5 March 2007 (UTC).
Yes, the model the criticism has in mind is garbage collection, where no-longer-referenced variables are reclaimed by the system, not requiring any explicit programmer action (such as calling free/delete). C does have automatic variables, but only within the stack-oriented procedure call hierarchy. — DAGwyn 23:45, 5 March 2007 (UTC)