In The Fallacy of High-Level Languages, Scott James Remnant argues that the advantages of languages such as Python, Perl, and C# over C are negligible -- and that they make programmers of those languages somewhat untrustworthy:
I trust code written in C far more than I do any higher level language. No, that's probably not fair. I trust C programmers far more than I do programmers of other languages. If you tell me I have the option of choosing a program or library written in C over one written in Python or C#, I'll take the C one every time.
Having contributed to a couple of high-level languages by writing C code to implement said high-level languages, I can't agree. I'm not here to praise C. I'm here to bury it. C has some tremendous disadvantages over high-level languages:
- Manual memory management. Yes, you should be able to match all of your
malloc()
andfree()
calls by reasoning about your program statically, but go write your own virtual machine which runs arbitrary programs with arbitrary memory requirements and see how well that works. Not every program is that complex, but not every program is that simple. - Cross-platform fun. Want your code to run on multiple platforms? Want to work around compiler and standard library and linker bugs on multiple platforms? Ever wonder why sometimes
memcpy()
gives you odd behavior when building with GCC with optimizations (and no, the source and destination don't overlap unless something has gone very, very wrong with whatmalloc()
- Poor abstraction possibilities. Yes, C has first-class functions (if you can remember the syntax for declaring the type of a function pointer -- I never can), but if you want new programming ideas such as closures, partial application, or continuations, you have to fake them yourself. Don't even mention allomorphism or a type system which encodes richer semantics than "How many bits is this on a PDP-11?".
Verbosity.
(Okay, I should say more.) Implement a bare-bones
grep
-workalike in Perl and in C sometime. Compare the two. (It'sdo { print if /\Q$pat\E/ } while <>
in Perl.) Now compare the rest of the boilerplate code -- and don't forget all of the code to handle errors in C.If, as much of the programming world seems to believe, the error rate per line of code is stable when comparing languages, perhaps there's a sweet spot at which a more expressive language will have far fewer bugs than a less expressive language. Put another way, I won't even feign surprise if you tell me that a Perl or Python program has a fifth of the bugs of an an equivalent Java program or a tenth of the bugs of an equivalent C program.
- Library support. As of this writing, search.cpan.org reports 66,704 available modules in 17,342 distributions. If even half of those are remotely useful, there are tens of thousands of libraries one
install Foo
away from any full Perl installation. There may be that many available C libraries somewhere, but show me a cross-platform installer which works with a globally mirrored hosting service with ratings, documentation, reviews, and a comprehensive and growing testing service.
I could go on -- projects such as HP's Dynamo and the Self programming language have demonstrated that runtime profiling and optimizations can improve performance over static compilation in many cases. As well, changes to the memory management of Mozilla Firefox 3.0 show that low-level memory manipulation can actively harm performance (arena-based allocation such as you might find in a system with an intelligent GC -- or even Perl 5 -- is much less susceptible to fragmentation).
I suspect that many people reading this have already made up their own minds, however. All I can tell you is my experience. I've never spent a couple of days optimizing a regular expression in Perl, and I've spent many days measuring and optimizing performance in C -- not to mention countless hours using gdb
, Valgrind, and KCachegrind. Don't misunderstand me; I'm grateful for those tools.
Yet I'll be more grateful for the day when I never have to use those tools again.