Popular C software is so reliable because of enormous amount of effort spent developing, testing, and polishing it over many years - not because error handling in C is superior to that in higher-level languages. If your python script sticks around for 30 years constantly being used by millions of people - I bet it will be rock solid as well. All other things [1] being equal [2], a program written in a higher-level la…
In a lot of ways, comparing syscalls like stat and Java methods is apples and oranges. System calls are at the very bottom of the stack, where userspace interacts directly with kernelspace, so they must return all error information, otherwise there would be no other way to get it from userspace. So it's not really examplary of C language style that syscalls behave this way. Syscalls are not designed to obscure what's…
How can C Programs be so Reliable? (2008)
211–220 of 230 posts
Re: How can C Programs be so Reliable? (2008)
#212Earlier quoted context omitted.
Most computing environments don't have a user to speak of, and the correct response of an application to an out of memory error could range from doing nothing to sounding an alarm. As a user, I find it incredibly frustrating when my old but indispensable music software runs out of address space (I have plenty of RAM) and, instead of canceling the current operation (e.g. processing some large segment of audio), just d…
I think most computing environments do have a user of, if you consider a "user" to be something that be notified and can act on such notifications (e.g. to close applications). Your music software's problem seems to be a bad algorithm - not that it doesn't check the return values of the `*alloc` functions.Aas you say, it should be able to process the audio in constant space. While I assume that I can always acquire m…
Just for fun, try deliberately creating a swap storm some time. Then try to recover from it :-). Do this on a system that doesn't have other users.
Re: How can C Programs be so Reliable? (2008)
#213Earlier quoted context omitted.
Exceptions are kind of like gotos, but worse, because the jump target is decided at runtime based on the state of the call stack and therefore cannot be determined just by looking at the code. So they're more like comefroms [0] than gotos. [0] http://en.wikipedia.org/wiki/COMEFROM
Right, which is why they are reserved for situations where you are not trying to "jump somewhere", but just want to give up and crash, because further execution in the current context has failed. If some external calling context really does not want to crash, the implementation of failing function doesn't and shouldn't care.
Re: How can C Programs be so Reliable? (2008)
#214Earlier quoted context omitted.
The other day I was quite surprised to learn that the first version of memcached was written in Perl - thinking something like that should be obviously written in C, or else could never make LAMP systems faster... :)
Why it's obvious an user-space daemon should be written C? It's a myth other runtimes don't have enough performance.
While it's very much possible to directly allocate and manage memory yourself in Java -- and I have done that ( http://mail-archives.apache.org/mod_mbox/hbase-commits/20130... ) -- but without memory safety guarantees, without the great tooling, without the general idea that "if your code compiles, it will probably work correctly". In other words, you're programming a very verbose and ugly (see DirectByteBuffer interface) C. There's many cases where this approach ("off-heap memory") makes sense when building memory intensive apps in Java that clearly benefit everywhere else from being written in Java: JNI is unpleasant to work with, JNA adds additional performance penalties on top of those imposed by JNI calls that it makes under the cover -- which is fine in many cases, but remember that reading files or sockets are also JNI calls -- but less so when you're building a system that distinguishes itself by being in memory.
On the other hand, if you use C (or "C+" a.k.a. "C with objects", or -- as I prefer to say to avoid confusion with libraries like glib or apr or the Linux vfs layer, all successful object oriented systems written in regular C -- "C with templates") you have accesses to the existing works (advanced allocators like jemalloc and tcmalloc don't work very well with JVM), excellent memory-debugging tools, and so on...
I will say this: I think more software rather than less should be written in higher level languages. I absolutely love OCaml, Erlang, and Lisps (especially those -- like Typed Racket and Clojure -- that have started importing features from Haskell/ML family), like what I see in Go. I use Python (and formerly Perl) on a daily basis for "casual programming", to experiment with new ideas, and automation. I've written a great deal of software in Java, where many people blinked the idea that this category of software could be more than a toy in Java. I think garbage collection could be great improved and I see no theoretical reasons why, e.g., compilers can't be written in OCaml as opposed to C or C++ (I do see practical reasons having to do with runtime, lack of multi-core support but that's a separate and fixable issue). I find projects aimed at making systems programming in high-level languages fascinating (e.g., Mirage OS, Microsoft's experiments, Jikes RVM, etc...)
However, even if these theoretical strides are achieved, there's always going to be room for C -- in the end, you need systems that give you great deal of control and act in a very deterministic and predictable fashion . In the mean while, however, there's also need to build practical systems -- so while C and C++ may not be ideal in theory, they are often the only realistic option in practice.
[1] Note, however, I didn't say anything about performance -- OCaml, Java, Haskell, LuaJit etc.. do well in the Debian benchmarks; Lisps follow those languages closely. Likewise, many high-level languages can be AOT compiled. While when written by a strong programmer and/or assisted by today's excellent optimizing compilers C will still beat these fast high-level languages in most cases, it should be noted that today it's extremely difficult to write assembly code by hand that beats assembly code written by an optimizing C compiler or even the JVM. I predict that when a language comes about that has a better designed type system than C/C++ and yet still provides ability to control memory layout much as C does, eventually compilers for that language will emit assembly code that beats assembly emitted by C compilers for the same reason compiler-written assembly beats hand-written assembly -- compiler is able to leverage the type information (declared or -- in the case of dynamically typed languages with fast runtimes -- inferred) to aid optimization.
Re: How can C Programs be so Reliable? (2008)
#215There are multiple factors that contribute, but here's a few that I haven't (to the best of my recollection) seen mentioned so far: tooling (crucial), "do the simplest thing that could possibly work" attitude brought about by (lack of) a built-in collections library and simple syntax, and lack of rapidly changing requirements during development. Tools for C are powerful, mature, and available on near every platform.…
> Tools for C are powerful, mature, and available on near every platform. Every single C programmer that I know uses multiple memory debuggers, for example: e.g., valgrind for leak checks and more on smaller code segments, LLVM address sanitizer on unit test runs, jemalloc or tcmalloc/google-perftools, and more. This is exactly the point. C developers need to make use of external tools to improve the language's flank…
On the other hand, memory leaks occur just well in memory-safe languages (looking at Modula-3, I see a WeakPtr type -- which is there for this very reason). Finally there are also many reasons to want to have manual control over memory -- which when using high-level languages, ends up looking very much like C programming (e.g., Unsafe module in Java). However, you're essentially on your own when doing this.
By the way, memory debuggers are just one example -- plain debuggers are another, tools for tracing the code execution, performance tuning, etc... are another. As are mature and universally available libraries.
I don't mean to disparage high-level languages: I greatly enjoy programming in them and would like them to expand. Yet we're talking about existing code -- and in this case, C's maturity and universality (as a "lingua franca" of programming) are unrivaled. Nothing stops one from using -- and enjoying -- both advanced high level languages and C.
Re: How can C Programs be so Reliable? (2008)
#216Earlier quoted context omitted.
> You can nest under if(thing!=NULL) but then you end up with indentation creep. I am not suggesting any nesting of anything. Repeatedly checking at the same indentation level. > You can use the goto pattern if you like but some folks will tell you that goto's are never, ever to be used. What matters more to you, getting stuff right or repeating adages that other people have said out of context? `goto` is probably th…
>> I am not suggesting any nesting of anything. Repeatedly checking at the same indentation level. This could be considered wasteful. You end up checking if something is NULL, if it is you jump to the cleanup code and immediately check again. Nesting may be more elegant. >> What matters more to you, getting stuff right or repeating adages that other people have said out of context? `goto` is probably the cleanest way…
It's true that there is an extra compare. I think it's a small cost for maintainable code.
> Then they need to read what the function is doing and understand it before they mess with the code, just like in any other situation.
Sounds great, however, the time they spent figuring out your haphazard, repetitive and confusing free() statements could be better spent somewhere else. When I said that my way is more "composeable" I meant that adding, removing, or re-ordering operations is a cheaper operation for the programmer. Follow this style and you'll spend less time trying to read and figure out code because it will fit the existing convention and will be bleedingly obvious where the buffers are released.
I may have been a bit hyperbolic with calling this "correct" or "supposed" however I didn't make up these conventions, I advocate them because I have seen them work really well and I have seen yours create mounds of inflexible spaghetti.
Re: How can C Programs be so Reliable? (2008)
#217Earlier quoted context omitted.
Don't you find performance suffers? AIUI this approach means you can only handle as many concurrent requests as you have processes, and the OS scheduler has less information to work with than if you were using threads.
Why do you need to handle requests concurrently when something like the disruptor pattern can handle 6 million/sec on a single core.
Re: How can C Programs be so Reliable? (2008)
#218Earlier quoted context omitted.
Right, but doesn't the error handling approach you describe mean allowing a whole process to fail whenever an error condition occurs, which would cause any requests that were being handled by other threads of that process to fail even though they were perfectly valid?
Can you really tell me that you know after an exception that the other threads are really in a well-defined state let alone 'perfectly valid'? Look at something like ZeroMQ that is being rewritten specifically to avoid the non-determinism inherent in throwing an exception. Once you're using threads it's pretty much anyone's guess as to what state the system is in at any point, add exceptions and it just gets worse.
I agree that unstructured use of threading primitives leaves you with an unpredictable system, but it's possible to build safer, higher-level abstractions and use those.
Re: How can C Programs be so Reliable? (2008)
#219Earlier quoted context omitted.
> Tools for C are powerful, mature, and available on near every platform. Every single C programmer that I know uses multiple memory debuggers, for example: e.g., valgrind for leak checks and more on smaller code segments, LLVM address sanitizer on unit test runs, jemalloc or tcmalloc/google-perftools, and more. This is exactly the point. C developers need to make use of external tools to improve the language's flank…
You're missing the point: in many cases, choice of C is not ideological but practical. I love Modula-3 and OCaml (and ML's incorporation of Modula's module system in general); yet I'm using C++ for the project I am working on. From even the purely technical point of view, despite all the features OCaml has that I enjoy, building this system wouldn't be feasible -- I need shared memory concurrency and multi-core suppo…
At least with C++ the language offers the mechanisms without external tooling, for doing safe coding, if one so wishes.
You can use arrays that don't decay into pointers, bounded checked arrays, proper strings, references for output parameters, automatic reference counting.
Re: How can C Programs be so Reliable? (2008)
#220Earlier quoted context omitted.
Right, which is why they are reserved for situations where you are not trying to "jump somewhere", but just want to give up and crash, because further execution in the current context has failed. If some external calling context really does not want to crash, the implementation of failing function doesn't and shouldn't care.
That might be what they are intended to be reserved for but the reality of what they get used for is much more of the "Jump Somewhere" sort.