Live data from Hacker News

How can C Programs be so Reliable? (2008)

tratt.net

121–130 of 230 posts

Re: How can C Programs be so Reliable? (2008)

#121
post #63

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 really going on by putting a friendlier interface on it; at some level you need the truth.

Having said that, though, there are aspects of C that could lend it to writing robust code. The concepts are concrete, for one thing. Despite the fact that high-level languages are designed to be easier to understand, I suspect that concrete concepts are inherently easier to grasp than abstract ones (and it doesn't hurt that concrete concepts don't leak). What C contributes is a concise and eloquent syntax for telling the machine what to do, with little waste. Some people argue that it's dangerous to control the machine directly without the compiler being able to watch over you; but not having extra annotations for strong typing and such makes it easy to see what's happening, and I think that concision and transparency is key to writing robust code.

Re: How can C Programs be so Reliable? (2008)

#122
post #49

There 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.

If only this was true for embedded platforms! I have no tools at my disposal aside from a vendor supplied debugger. No pre-existing test infrastructure exists, what we have we have had to build up ourselves.

One of C's last remaining strongholds is in embedded, and the tooling in this world is atrocious! (Though some of the instruction and performance profiling tools are beyond amazing!)

Rigorous coding standards and a heavy reliance upon code reviews keep a code base clean and sane, sort of like on any other project written in any other language!

Re: How can C Programs be so Reliable? (2008)

#123
post #17

The author makes a good point about the discipline imposed by not having exceptions. Programmers tend to write code in one of two modes: the quick-and-dirty mode where you consistently don't check return values, or the built-to-last mode where you consistently do. If you start in the first mode and have to fix a bug, you often have to add error checking all up and down the call chain from where it occurs to where it'…

Well I think this is only a problem with runtime exceptions. You have no choice but to deal with compile time exceptions (of course you can deal with them poorly if you choose). But it seems the compile time exceptions are unpopular. I think there's another way to deal with this and that's a better type system. AFAIK it's impossible to have a null pointer exception in Haskell. EG: If you do something like `hashmap.ge…

Haskell does not force you to handle the value not existing. For example, you can do:

let Just b = HashMap.lookup k xs

If the element is not there, then lookup will return Nothing, which will fail to pattern match with 'Just b'. This can also be accomplished using the fromJust function. What Haskell does do is make it obvious where these exceptions can occur by documenting what functions can return Nothing, and by requiring you to explicitly cast between values that may be Nothing and values that cannot be Nothing.

Re: How can C Programs be so Reliable? (2008)

#124
post #110

Earlier quoted context omitted.

The problem with exceptions (in certain contexts, of course) is precisely these assumptions. Changes in low-level routines can change what your function is able to handle. Sometimes "just let it crash" isn't an option, period. Often, the exception hierarchy doesn't expose enough information to handle an exception without outside context (vis Python's OSError). In many cases, exceptions are superior to returning error…

"I've yet to see a universally applicable error handling model, and I suspect I never will." I'll bite: http://www.gigamonkeys.com/book/beyond-exception-handling-co...

Common Lisp's condition/restart system is very nice. It solves the context problem, which (at least in my experience) is the biggest problem with exceptions in day-to-day programming.

CL's dedication to the debugger also greatly reduces the downsides of not explicitly handling errors. You get the ability to notify the user of problems that they might be able to resolve manually for free.

The lack of function signature information is still a problem, though. Sometimes you really do need to know what exceptions might be thrown. There's also the issue of overhead . . .

I'm happy to say that exceptions are nice to have, but the idea that they're superior to returning error codes at all times in all places (especially in a language that supports returning multiple values) is more than a little silly.

Re: How can C Programs be so Reliable? (2008)

#125
post #63

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…

> Most sane languages [3] give you exception hierarchy Go being a glaring exception -- and this is a good thing.

I disagree. Go errors aren't even error codes. The error interface is just one method that returns a string. The only advantage Go has over C is that the errors are no longer inband with normal return values. Once you get one though, you're back in the perl5 land of reasoning about your error by scraping a string. I'm completely baffled as to why they didn't attempt to bundle more machine readable information into the errors.

Re: How can C Programs be so Reliable? (2008)

#126
C also has "better" I'd argue that average person programming in C is more matured, and understand nitty gritty of programming, computer science, performance and how things work at low level far better than, say, Visual Basic or even Java programmer.

I think we have been putting too much faith in to languages. After certain level of sophistication, the weight of quality shifts to person programming in it instead of language itself. However most language designers would tell you that their holly grail is to shift this threshold so programmers can be as lower in skills and ignorant as possible while quality of program as high as possible.

Lot of these things can be also said for JavaScript. I've now coded fair bit in plain JS constantly avoiding temptation to use some other language that compiles to JS (and even avoid TypeScript for that matter). Just 100% pure JavaScript. And I can tell you that my habits and flow is very different when I code in JS. Back then I though coding in pure JS would blow everything up just because of lack of types or silly thing like missed semicolons or as simple stuff like forgetting to pass 10 in parseInt. The fact is that none of these bothers me at all anymore. I rarely find bugs that can be attributed to these deficiency in JavaScript. Strongly typed languages now feels like some kind of over hyped hoax.

Re: How can C Programs be so Reliable? (2008)

#127
post #26

Earlier quoted context omitted.

> Needless to say, calling exit() when a call to malloc() failed wasn't an acceptable recover routine. What do you do when malloc fails? A bit of graceful shutdown and logging seems like it would be in order, but otherwise how do you keep rolling if mallocs start failing? It seems to me like that would indicate something has gone unusually wrong and full recovery is futile.

The most common way to indicate that an error has occurred in a C function is to return non-zero. If this is done consistently, and return values are always checked, an error condition will eventually make its way up to main, where you can fail gracefully. For example: int a(void) { ... if (oops) { return 1; } return 0; } int b(void) { if (a(...) != 0) { return 1; } return 0; } int main(void) { if (b(...) != 0) { exi…

It's not so simple in real life. I use this style of error-handling for only one type of project: a library with unknown users. In that case, as I can't make assumptions about the existence of better error handling systems, it gives the most flexible result. But at a price, I know have to document the error codes, and I had damned well better also provide APIs that allow my client to meaningfully recover from the error.

In most I have worked on, this type of error handling is completely inadequate. Think multithreaded applications. The code that needs to handle the error your code just generated isn't in the call stack. This happens very often in my experience, and I have found that the best solution is to post some kind of notification message rather than returning an error code. This creates a dependency on the notification system though, so it's not always the correct solution.

The thing that I dislike the most in your example was when you propagated the error from function a out of function b. my most robust code mostly uses void functions. Error codes are only used in cases where the user can actually do some meaningful action in response to the error, and feNkly this is rarely the case. Instead I try as much as possible to correctly handle errors without propagation. It frees up the user of my APIs from having to worry about errors, and in my opinion thus should be a design goal of any API.

Re: How can C Programs be so Reliable? (2008)

#128
post #125

Earlier quoted context omitted.

> Most sane languages [3] give you exception hierarchy Go being a glaring exception -- and this is a good thing.

I disagree. Go errors aren't even error codes. The error interface is just one method that returns a string. The only advantage Go has over C is that the errors are no longer inband with normal return values. Once you get one though, you're back in the perl5 land of reasoning about your error by scraping a string. I'm completely baffled as to why they didn't attempt to bundle more machine readable information into th…

Go errors are machine-readable data.

Most modules expose variables with the naming convention Err... that represent the errors that they can return. The errors can be compared with those values (eg. err == os.ErrPermission). Some modules also define error types that provide additional error data, such as net.OpError; a type-cast can be used to check if the error is of that type, and then access the data within. As a fallback, all errors implement the Error interface which allows you to display them as a string if you can't handle them based upon their type.

It's not unlike exception handling by exception type, although it's definitely more of a manual process because Go doesn't give you specialized syntax for it.

Re: How can C Programs be so Reliable? (2008)

#130
post #49

There 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. If only this was true for embedded platforms! I have no tools at my disposal aside from a vendor supplied debugger. No pre-existing test infrastructure exists, what we have we have had to build up ourselves. One of C's last remaining strongholds is in embedded, and the tooling in this world is atrocious! (Though some of the instruction and perfo…

Embedded test software is developing. Look at http://throwtheswitch.org/ and my (more minimal) "greatest": http://github.com/silentbicycle/greatest
Post reply on HN