11 ms·
Why Systems Programmers Still Use C (2006)
- alpad 15y agoInteresting article, but he misses the right answer: if it isn't broken, don't fix it. C may not be the easiest language to learn, but you wouldn't want newbies messing with systems programming anyway. Higher level languages give you a more abstract view, but when you are doing systems programming that's not what you want, you need to be in full control. Only C gives you precise control of what the machine is doing all the time. You don't want a garbage collector to kick in unexpectedly, you don't want data structures to be allocated in mysterious ways.
- willvarfar 15y agoOn the other hand, again and again bugs that come from the ability in C to alias have been exploited. His answer was of course EROS. Microsoft explored Singularity. Some of his colleagues went and wrote Go as a systems language (if not a kernel-side language).
- moonchrome 15y ago>You don't want a garbage collector to kick in unexpectedly, you don't want data structures to be allocated in mysterious ways. All of that (and everything else C is attributed with) can be accomplished without using an arcane preprocessor/include system and you can have niceties such as a saner type system, generics/macros, namespaces, etc. C is a language stuck with the design decisions that reflected the programming environments in the 60's and 70's but make absolutely no sense in modern context and now we are just stuck with it because of inertia.
- chipsy 15y agoI would agree and would elaborate that the major weaknesses of C are a combination of build system issues and an overly weak type system. It wasn't realistic to have the whole compile process done in memory in the early 70's, and OS virtual memory wasn't realistic either; but we've long surpassed those concerns, and that means that all the thinking about the program namespace, modules, linking, pre-processing, etc. is worth re-evaluating. As well, we can do better static checking now, without including any notion of GC; in an imperative execution model, leakage of memory, handles, processes etc. remains orthogonal to type safety. C has heavily bottlenecked program control logic from the beginning - a callstack, looping constructs, etc. - and allowing some equivalents to exist in its data structures would make user code tremendously more reliable. These changes, often paired with some more attention to concurrency, show up in all the newer system language designs - D, Go, Rust, Clay, BitC, etc.
- CJefferson 15y agoAnyone who tries building a better C (for example Go) seems to end up going "too far", and as well as fixing the things you mention, ends up adding garbage collection, and various other things which are not suitable for very low level systems programming. I teach C, and I would love a "cleaner C" mode, which just got rid of lots of the bizareeness of C, several of which you mention. The fact that many compilers will warn with '-Wall' about code which is clearly incorrect, but due to the rules of C they cannot simply reject, is irritating.
- queensnake 15y ago(add -Werror - your students will never know.)
- pjmlp 15y agoFact is there are many examples of operating systems implemented with GC enabled systems languages. Spin, Oberon, Singularity, Home are just a few of them. The main problem is that for a systems programing language to be used a such, there much exist a successful operating system that uses it as its main language. In Windows 8, the main systems language is C++/CX (C++ with reference counting extensions), so the time will come.
- cygx 15y agoThe fact that many compilers will warn with '-Wall' about code which is clearly incorrect, but due to the rules of C they cannot simply reject, is irritating. The rules of C are actually stricter than many reople realize (add -std=c99 -pedantic-errors to gcc and you can get an idea about that -- this, however, still won't catch semantic errors like aliasing violations). Personally, I'm using clang with -Weverything and remove warnings as necessary. On gcc, there are a lot of useful warnings which are not included in -Wall. My current warning levels look like this: -std=c99 -pedantic -Werror -Wall -Wextra \ -Wmissing-prototypes -Wmissing-declarations -Wshadow -Wpointer-arith \ -Wcast-align -Wwrite-strings -Wredundant-decls -Wcast-qual \ -Wnested-externs -Winline -Wno-long-long -Wconversion -Wstrict-prototypes
- javascriptlol 15y ago"Only C"? What about Forth?
- rntz 15y agoYou misunderstand his argument. He's not arguing that we should replace C with "higher-level languages" that don't give you precise control of the hardware; in fact, he bemoans the fact that the PL community at large seems interested only in such high-level languages. Nor is he complaining that C is hard to learn (I'm not sure where you got that impression). In fact, the paper mostly takes for granted that C needs to be replaced, and discusses the challenges in doing so, which may be why you assumed that BitC is (was, really) just another typical research-community high level programming language project. The fact is, C is broken, and we all suffer every day because of it. From a security perspective, C is a nightmare. It is not just an unsafe language (in the PL sense of having undefined behavior), but a rampantly unsafe language. Null pointers (which C.A.R. Hoare famously called his "billion-dollar mistake"), buffer overruns, unrestricted pointer arithmetic, arbitrary casting, manual memory management; all of these are the cause of innumerable bugs in real code, often critical security vulnerabilities. C is also not the nicest of languages to code in. It is terribly verbose. There is no good way of writing generic code in it. The preprocessor is a gigantic ugly hack. Writing portable C is a pain in the ass, and building it portably is doubly so. The worst part is, we know reasonable ways to solve most of these problems. In many cases we have known them for decades. Unfortunately, how to best integrate these solutions into a language and still keep it useful for systems programming was (and is) an open problem. I can't speak for Shapiro, but as I see it this is what BitC was aimed at doing.
- anon_d 15y agoC is far from "terribly verbose".
- quanticle 15y ago>Only C gives you precise control of what the machine is doing all the time. Maybe in 1979, it did. Modern C compilers alter and modify code quite radically, to the point where it's quite difficult these days to go back from optimized assembly back to the original C code. These days, C gives you a good illusion of control, but all too often, C programmers mistake illusion for reality.
- ajross 15y agoNo, C gives you control. I have a syscall (bind(), say) that takes or returns a polymorphic array via a pointer. How many "system" languages represent something like a C pointer cast or union type with clear storage semantics? Or I want to write a code generator for my fancy new language interpreter and need to call mmap() to get an executable range. How many "system" languages let me call into that memory with native syntax? What you're describing is the difficulty in understanding what the guarantees of control are that you get form your compiler (and yes, that's a much more involved issue than simply reading a language spec). Yeah, C is hard. But the fact that you don't understand how the optimizer works (or how to read the generated assembly) isn't the work of an "illusion", it's just your own inexperience.
- edwinnathaniel 15y agoThese days Java seems to become one of the choices to do system programming in a different area/level: HBase, Hadoop, Cassandra, GWT tools, MQ, App Servers (Jetty, Tomcat, GlassFish, etc), EhCache. Unless if people categorized the above software as non-system-programming.
- heretohelp 15y ago>Unless if people categorized the above software as non-system-programming. Probably the case, networked services represent an area where performance is at least somewhat a concern, but BitC is trying to address situations where one is writing a memory allocator, not building a server on top of a GC'd language known for having sloppy memory usage.
- jandrewrogers 15y agoMost database engines of moderate sophistication straddle the "systems" and "application" line because they start directly managing system resources at a low level. Application servers are a bit more like "applications". Database engines highlight some of the reasons that Java is a poor systems language relative to C/C++. High-performance database engines these days are usually bottlenecked by memory I/O performance and efficiency, or storage I/O if you under-provision the machine resources for the workload. This is why you see I/O optimizations applied to in-memory databases, for example. Java may be fast at many things, but it is much slower than C/C++ for codes that are bound by memory performance and efficiency. You have to start doing very awkward things in Java to even come close to what comes naturally in languages that explicitly manage memory behavior and structure. As someone who has written a lot of database engine-y code in both C++ and Java, the difference in absolute performance for nominally equivalent code is not small, and is generally easier to achieve in C++. So for low-level performance-oriented systems, there is a pretty strong bias toward C++, particularly now that there is a lot of experience trying to implement the same systems in Java. For performance sensitive codes, systems programming is really about carefully managing resources to optimize for characteristics of the system. C makes this very easy because it exposes all of it. To the extent that CPU architectures are increasingly bound by memory performance, I would not be surprised to see C++ supplanting Java for certain purposes. This makes sense. Java was designed more as an application language that works well for codes that are unlikely to make heavy use of the memory system. Its popularity and generality has caused it to be widely used but that does not always make it a good choice outside of its original design case (see also: Perl).
- javascriptlol 15y agoThe problem with systems design is that it's all so complex. Multitasking has become an excuse to run everything as some absurd daemon. Badly designed hardware has to be papered over with undocumented binary drivers. Everything is optimised for throughput benchmarks, so we get warm ups and unpredictable pauses visible to the user. And it's all full of security holes. The plain truth of the matter is that none of these things are due to a lack of special language support. It's that the whole system is too complex, and the complexity isn't even quarantined in such a way as to be harmless. We need to be able to start over (something the author acknowledges). We can't do this if we build yet another complex system in the belief that we'll get it all right this time round.
- eli_gottlieb 15y agoBut that would break the backwards compatibility with previous systems and architectures. The markets can't have that.
- ehsanu1 15y agoThe problem with that is "Worse is Better". And there's just so much momentum behind current technologies, that switching seems almost unimaginable to most. Can you imagine not having Unix-like systems, and not being able to use C and all the languages built around that ecosystem? But if you're looking for a replacement for the entire software stack we use today, one that tries to shun complexity (20k LOC for everything from kernel to common GUI apps), here you go: http://www.vpri.org/pdf/tr2011004_steps11.pdf http://www.vpri.org/pdf/tr2011004_steps11.pdf More info (see previous STEPS reports): http://vpri.org/html/writings.php http://vpri.org/html/writings.php
- javascriptlol 15y agoThanks for the link. I will check this out later. >Can you imagine not having Unix-like systems, and not being able to use C and all the languages built around that ecosystem? Yes! Charles Moore has been essentially living this since the 1970's. No many have his level of courage though.
- javascriptlol 15y agoAlso, this paper suggests that the answer to multi-tasking problems is to move the complexity out into the language. It's funny how PL researchers will always spin the situation so that it demands more PL research. If we're really moving into a many cores future as people suggest, then we should have architectures that give each application a dedicated core. No context switching. Of course, you'd need a simple system and not a billion daemons running in the background waiting to be exploited by criminals.
- tmurray 15y ago"If we're really moving into a many cores future as people suggest, then we should have architectures that give each application a dedicated core. No context switching." You probably don't want that either because the cost of moving data between cores will be so high from both a performance and a power consumption POV. The days of free coherency between cores will eventually come to an end; you can already see evidence of that in multi-socket Intel and AMD machines (if you try to ignore the NUMA nature of memory, you swamp the link between sockets and perf tanks in a variety of apps).
- javascriptlol 15y agoWhy would you be moving data between cores? I'm talking about an arrangement where each core is dedicated to a single program. No sharing of memory, even via the kernel. Each hardware devices talks to a single core only. Multiplexing of hardware would be done in.. hardware. For all intents and purposes the "core" could be out on the network. All this throughput nonsense is benchmrk lies. Websites are not as a general rule highly responsive. They have huge variability in response times. Who cares if it costs a bit more to run the system if it means having a nice predictable system built for simplcity and safety from the ground up?
- jedbrown 15y agoYou need an event-driven system because the number of "tasks" rarely matches the number of physical cores available. One tried and true, fault-tolerant event-driven interface is provided by the kernel: processes (and threads). It has interfaces for binding to NUMA regions and such. Any system you design will have to tackle a lot of the hard problems that kernels deal with. Now maybe you have a simpler system in mind, but it has to be drastically better for anyone to consider giving up binary compatibility.
- halayli 15y agoThings I can think about: - low level memory management - faster execution (in most cases) - cache line optimization - avoiding language implementation magic
- andrewflnr 15y agoWe are starting to get alternatives, though. Besides Rust and D, there are Clay (http://claylabs.com/clay/ http://claylabs.com/clay/), ATS (http://www.ats-lang.org/ http://www.ats-lang.org/), and Deca (http://code.google.com/p/decac/ http://code.google.com/p/decac/). I'm sure there are more. I unfortunately haven't had time to play with them, and they're in various stages of development. But at least people are thinking about improving systems programming.
- signa11 15y agowhy fix something that is not broken ? with systems programming you wouldn't want anyone/everyone to mess around with it anyways. i don't need bound-checked-arrays, or or garbage-collection (oh the humanity!) at random unpredictable times. c gives an unprecedented level of control over what the machine is doing, for more abstract level interface to the machine, use whatever suits your fancy...
- ijt 15y agoI was surprised that the author thinks the syntax of Haskell is no better than that of C++. Let's look at a typical example. In Haskell, the signature for sort is sort :: Ord a => [a] -> [a] which just says that it takes a list of comparable things and returns another list of the same type. Here's the type signature for sort in C++: template <class RandomAccessIterator, class Compare> void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp ); The difference in terseness and clarity is a big reason why I use Haskell when I have a choice.
- ajross 15y agoPlease. The difference in terseness and clarity is made up almost entirely of the lenths of the symbol names: template<class I, class C> void sort(I a, I b, C cmp); Now, the concepts aren't 1:1; Haskell for obvious reasons doesn't represent the idea of operating on storage directly, so you can't have an iterator and need to return a "new" list. C++ makes you write out the types you are parametrizing instead of getting it implicitly. And there are no doubt some really good arguments why Haskell is terser and clearer than C++. But this isn't one of them. Come on.
- ijt 15y agoThe difference is not only due to identifier length. Haskell's sort is a function in the mathematical sense. By looking at its type, I can see the input and output at a glance and understand how to use it. It's not immediately obvious from the signature of the C++ sort procedure that the "first" and "last" arguments are being used for both input and output. When you abbreviate the identifiers for STL sort it's even less obvious what's going on.
- ajross 15y agoThere's nothing "immediately obvious" to that Haskell signature at all. You need to understand the [] syntax for list typing. You need to understand that the language defintion has a built-in notion of "list". You need to understand the idea of functions having types themselves (a huge hurdle if you're new to functional languages). And you need to understand that weird "Ord" decorator gadget and that it means the types can be compared. Basically, you can't understand that line noise at all unless you know Haskell. Duh. Likewise, if you're truly confused about C++ STL iterators you're just waving your own ignorance around. They're a simple concept pervasively applied in the library. No experienced programmer is going to be confused by that function declaration. Look, very good cases can be made for functional languages. But this is just surface-level stuff that frankly isn't going to help anyone. Expressing a sort simply isn't a complicated thing in C++ or Haskell and trying to claim otherwise is just dumb.
- SkyMarshal 15y agobitc appears to be abandonned, but I cloned it from their hg repo and put it up on Github anyway. Here it is, for posterity: https://github.com/bitc-repos/bitc https://github.com/bitc-repos/bitc Projects like this make me wonder if they would have gotten further had they put it on a more social oss hub, be it Sourceforge in its day, or Github now.
- webreac 15y agoI have stopped when I read "The concrete syntax of Standard ML [16] and Haskell [17] are every bit as bad as C++". The author definetely has no understanding of PL issues or has a huge bias toward C++ insane syntax.