Hacker News new | past | comments | ask | show | jobs | submit login
Taking C Seriously (subfurther.com)
127 points by tomh on Nov 2, 2011 | hide | past | favorite | 58 comments



I'm confused. Did C stop being taken seriously at some point? C is the only language that you can truly get things done without having to fight the language every step of the way.

I can't say the same of... well, any other language I've used in the past 5 years.


agreed. and if you do any sort of embedded work, you must know C and C++. If history is any predictor of the future, chips will continue to get smaller and the "embedded" development world, I think, will proliforate and demand coders to know C and C++ at least for the next several years until fancy tools/compilers argue things like Java and C# code bloat doesn't matter because a 4Gig embedded system will be the norm... ahem..


There is a huge swing against C++ in the embedded world since 2007 or so. ABI issues, etc.

Not saying it disappeared, but there is now a bifurcation between C and C++ programmers.


Perhaps a better title would have been "Don't take C for granted."


>C was developed between 1969 and 1973, making it nearly 40 years old [...] C ha[s] already made an exceptionally good start on a century-long reign

In all fairness, development continued past 1973. Most C programmers today would have some trouble even reading the code from the 1978 first edition of K&R; and the void* pointer, that the author refers to later in the article, was a part of ANSI C (~1990).


Development on C hasn't stopped. C1x is coming soon (probably 2012 or 13), and has a lot of interesting enhancements including bounds checking.


According to Herb Sutter's obit for Dennis Ritchie ( http://herbsutter.com/2011/10/12/dennis-ritchie/ ), C1x already passed its final ballot, so all that's missing is an official announcement.

It would be nice to know if there are any changes from the April draft, though...


Bounds checking is just for library functions, and there isn't something like automatic array bounds checking, right?

Still, whoa -

    > #define cbrt(X) _Generic((X), long double: cbrtl, \
    >                               default: cbrt, \
    >                               float: cbrtf)(X)
Fun stuff.


Definitely. Occasionally I'll run across some code in an old program (eg: Emacs), and be utterly unable to read it, because it's an older dialect of C (that I'm surprised most compilers still accept). I'll have to dig out a copy of K&R first edition just to read the code.


Pure C seems to be enjoying a bit of language fad hipness lately but I don't know anybody that has to maintain a large body of non-trivial, low-level code that chooses pure C over C++. There's a good reason that everything from Solaris to V8 to Photoshop to Quake is written in C++ and not C.

That C is still in wide use after 40 years is a testament to the elegance of its original design but let's not get carried away.


The Linux kernel, Subversion and PHP are pure C. And don't get me started on the BSDs or binutils... ld and libbfd are pure C and its C++ replacement (gold) is still not widely used.

And this came without thinking about it... surely in two more minutes or by going to ohloh I could fire a couple more large bodies of non-trivial low-level C code at you.


"Subversion"

And don't forget Git! ;)


...because the environment precludes changing? Back when I was pressed into Linux work (years) C++ keywords were used as variable names in standard headers. Made it pretty obvious nobody had ever, ever tried to use C++ for Linux code.

I tried writing Linux kernel drivers; it was a horrifying mess. Tragically, it would have been easily managed in C++.


> The Linux kernel, Subversion and PHP are pure C. And don't get me started on the BSDs or binutils... ld and libbfd are pure C and its C++ replacement (gold) is still not widely used.

Please pick gcc to mention or, indeed, any other C program ever written, before libbfd ;)


But then, the new star (clang/LLVM) is written in C++.


>I don't know anybody that has to maintain a large body of non-trivial, low-level code that chooses pure C over C++. There's a good reason that everything from Solaris to V8 to Photoshop to Quake is written in C++ and not C.

How about the Linux kernel?


And all the BSDs.


I've consulted in the past on embedded projects. In my experience, maintaining a non-trivial body of C++ code is easily a factor of 2-10x harder than maintaining equivalent C code.

I have lots of reasons why this is true, many of which are specific criticisms about C++. There is one issue that is industry specific: Everyone working in embedded has either come from the bottom up (deep firmware in assembly or machine code) or the top down (Java in school), and when you get a dozen people where half of them treat C++ like "C with classes" and the other half treats C++ like it's Java, it's a guaranteed disaster.


Then why doesn't somebody clue in Adobe, Ableton, Epic Games, Pixar, Valve, Google etc and get them to abandon their wicked C++-loving ways? If what you say is true in general then you could save a lot of the brightest engineers in the world a lot of headache.


The reason why games are written in C++ is because the gaming industry was sold on the idea in the mid 90's and now all the tools are written in it.

For low level systems work, C++ can be considerably more difficult than C to organize and port large programs.

It isn't "C++ is always worse than C" it is "C is often better than C++ for a given task, depending on task"


Also, win32 is a C++ project. There are significant advantages to writing in the same language as the underlying platform.


Solaris is written in C. Same is true for all BSDs, PostgreSQL, nginx and a lot of other high-quality software.


Quake was not written in C++. All of id's games until Doom 3(2004) were written in C.


I think, wolf 3d is C++ too.


Why would you think that? That was their first FPS released way back in 1992.

If you are thinking of Return to Castle Wolfstein, that was C as well, using the Quake 3 engine. But id didn't even make that game.


I'm sorry, you are right, it was indeed in C.


http://www.tarsnap.com/kivaloo.html

The author is pretty active here on HN. Very well documented design and goals. Also well documented for what problems it does not solve.

I think around 20k LOC. Seems pretty non-trivial.


All RAD's products are pure C at the interface level. Most of them are pure C at the implementation level, too. The one exception is that Telemetry (which I work on) uses C++ to implement the C interface, but only minimalistically.


I've had the pleasure of integrating your Granny SDK into our engine at the indie iOS shop I work at and it's been a total pleasure to work with and a perfect example of solid C interface design.

Now when can we get telemetry support? ;)


You're in luck! I ported all of Telemetry to OS X (including the visualizer) a few weeks ago, and next week I'm planning on porting the run-time to iOS. With those two big pieces finished, that should give iOS developers a full solution. There's going to be a pure bugfix/stability release early next week, and the release after that should have the iOS goodness.


Hi, I'd like to chime in as an embedded sw dev. We're still there, designing your equipment, coding quietly and happily in C... :)


Something about most C++ code I've read makes me a little sad. It's a great language, but many features seem to be abused.


Quake, Quake II and Quake III are C.


Some good counter-examples but these are outliers. You can't seriously argue that the vast majority of big, high-performance apps aren't written in C++ and for good reason. Cubase, Photoshop, Maya, Renderman, Chrome, Java/JVM, virtually all A-list video games etc.

People have codebases that are millions of lines of code in C++ that I don't think would even be possible in pure C.


You subverted your argument by including the term 'low-level'. Of course, that's all written freshly in C to this day.

Assuming that you meant only 'non-trivial': aside from the embedded space, C and GCC still represent the first-tapped resource in many companies. C is terse, well-known, fast and predictable.

I'd go marginally further and claim that, done correctly, gmake and a proper directory hierarchy remain the most effective way of organizing and maintaining a large software project.


Saying that "TIOBE rankings are at least the best system we currently have" for gauging uptake of a programming language is like saying that astrology is the best system we have for predicting the future.


It would be interesting - but a lot of work - to add "time to modify" and "time to debug" metrics.

Each task would come with a modification, and an error to make in implementing the original task. You'd recruit undergraduates, who hadn't used the language before. Some would be given the original program to modify, others the broken version to fix. You'd measure how long they took to do it.

This way, language communities that gamed the machine benchmarks would pay a price on the human ones.


Yes, because untrained undergraduates are the programming workforce in every industry, especially aerospace and medical device makers.


Hello, "Enterprise"? Beam me up, there's no intelligent life here.


Those TIOBE numbers (linked to in the article) are quite interesting.

As well as C refusing to go away, there's a noticeable surge for C#, Objective-C and Lua, and a substantial erosion in the popularity of trendy languages like Python and Ruby.


Lua is small and embeddable. You can run multiple independent instance of it in the same process. The lua table is a very useful data structure.

Then you have luajit - also a small, easy to embed solution, that approaches standard "C" written code, and it's main weakness, from what I understood (Mike Pall had a post about it) is it's garbage collector.

On top of that, ffi bindings make "C" calls extremely fast, when the jit is active, and not very bad when the interpretter runs (but slower).

And the lua/luajit license allows you to embed it in your application, without the need to share source code.

Mike Pall is working on ppc, arm versions (and I think there might be already ppc jit).

Not last to forget - awesome community (comp.lang.lua).


Using LuaJIT with minimal FFI C code to optimize, seems to be the best way forward in maximizing both performance and maintainability.

What would be really interesting is to see someone highlight specific cases where this approach ultimately fails to measure up in performance with using pure C.

I would think that the LuaJIT approach would be tens of times more maintainable for a sufficiently large application, so it's really imperative here that we ask 'Why not?'


You can always find cases where it would fail. And that's ok. For what it's doing, and what it allows it's simply unbelievable (at least to me) how it succeeds in doing it (I understand very little of compilers, and little of interpretters).

One area which is not easy translatable is OpenMP (www.openmp.org), inlined assembly, and SSE packed floats. But that's okay, and even then there is probably a better alternative - a language more suited to such tasks, instead of "C" - OpenCL (www.khronos.org) or DirectCompute.

But for general coding, it's very very good.


The odd thing is TIOBE shows a general decline in JavaScript beginning in mid 2009. Even if the index is just a count of search engine results, this feels like exactly the opposite of what's happening in the real world.


Whoa, that page is hard on the eyes....I didn't get far in that article, but I think C has continued to live on as well as a foundation that has spawned other great languages. I don't see it (or variations of it) going away anytime soon.


The problem is, nothing in this article even begins to address the actual criticism people have of C, instead saying that it's possible to write good C code and that Java is a memory hog. The first is true, the second is debatable, both as to whether it's the case and whether it matters.

For example, read this: http://www.jwz.org/doc/gc.html

> In a large application, a good garbage collector is more efficient than malloc/free.

My point isn't necessarily to disagree with the article, but to point out that the article has practically nothing to disagree with. It has no substance.


Yeah, the article is just praise of the minimalist C style I guess.

To elaborate, the actual problem with C is that you have to deal with ownership semantics manually. In languages with things like uniqueness typing or automatic reference counting that problem goes away. Common to all these languages and all GCed languages is the need for memory management--clearing references or maps or just generally indicating (with the language's particular idioms) its lifetime. Sometimes in a GCed language all that ownership gets untangled for you for free, but this may actually be a maintainability hazard. A trivial change might suddenly start retaining objects forever. See Haskell, where a seeming perfect program may suddenly gain space leaks upon mere removal of, say, a print statement.

Some GC implementations might be faster in practice if they can move around memory and improve cache locality and reduce fragmentation. On the other hand, some introduce long collection pauses (often an issue with C# on XNA for example), and the default malloc() on many systems is very slow and tends to fragment. But "sufficiently smart" GCs avoid these issues.

Ideally the solution is a hybrid approach: for data with obvious lifetime (bound to a scope or a certain area of the program execution) you want to actually show those intentions in the code or types. For short-lived objects that you're working with or object graphs you want garbage collection. This is what generational GC simulates, but I always find it asinine to fiddle around with references (possibly having to null out) and deal with non-deterministic deallocation when the lifetime is clear. Sigh. One day.


Every time I think about writing anything substantial in C I think about manual memory management and error handling via error codes and I quickly shelve the idea.


Any time I think about writing anything substantial in a language with exceptions, I think about non explicit exiting from my function and I quickly shelve the idea.


Zawinski's point is true iff "large application" means an application which allocates and frees plethora of tiny chunks -- however I will argue that this is not a necessity, rather a style coming from a try to port scripting experience to lower-level languages to speed up development. Probably in most cases this is not a problem (no one will notice 100us speedup in GUI), but if one starts to tweak GC or new to rescue efficiency or argue which is better, it is certainly better idea just to write it in C, with all those ugly buffers and pointers. If you already have to track memory use in your mind, why not to just take control of it?


Because then you have to control ALL of the memory, not just the data that you're interested in optimizing. Not to mention that (at least in the JVM) the gc is pretty tweakable, and the entire team may not need to know about all of the tweaks.


This is precisely how it looks from this "microallocating" perspective.


JWZ also states "Java and Emacs are really bad examples of GC-oriented environments." in that same article.

And later, in 2000, he states "Today, I program in C." http://www.jwz.org/doc/java.html

JWZ is an entertaining read, but unless he's updated in a post somewhere in the last 11 years, it isn't clear to me where he comes down on C at the moment.

Btw, I program in C.


From the "Coders at Work" interview in 2009, JWZ says that he mostly writes Perl scripts for small one-off tasks, and every now and then a new screen-saver in C.


> it isn't clear to me where he comes down on C at the moment

At the moment, his main focus seems to be his bar, so perhaps he isn't the best person to ask about the relative merits of C versus modern garbage-collected runtimes.

Not really the point, though: The point is that blanket statements about the inefficiency of gc amount to superstition, and should not just be let stand.


Wow, talk about strawmen:

> for a large, complex application a good GC will be more > efficient than a zillion pieces of hand-tuned, randomly > micro-optimized storage management

vs:

> Note that I said a good garbage collector. Don't blame > the concept of GC just because you've never seen a good > GC that interfaces well with your favorite language.

Ok, so we're comparing 'state of the art GC' to 'zillion pieces of hand-tuned, randomly micro-optimized storage management'. Astoundingly, we come to the conclusion that GC Is Awesome and MOAR Efficient.


In other words, he's comparing what we're likely to get with a large C project and what we're likely to get in a modern garbage-collected environment. I don't think he's claiming more than that; where's the problem?


Having practical experience working at a company that has a large number of developers trying their stab at C, I'm bound to agree.

It's clear that you can make great code in C, if you're a good programmer and get enough time to plan things like memory management done right. Enough examples of that.

But when you don't, C is a terrible language. It is very verbose, it makes you repeat yourself and the macro system is so error-prone to the point that it's usually forbidden to use. So you have to resort to custom code generators (we have at least three!).

Most companies don't want to be in the business of worrying about buffer overflows and memory leaks and segmentation faults. They want the requested functionality implemented robustly ASAP. If there is less code to be written, there is less to test and worry about, so a high-level language that takes those concerns (largely) away is a great help.

So my advise would be to limit using C to the performance-critical parts (found using benchmarking), and only make developers work on that which understand every detail about C. Also, give them enough time to test every nook and cranny threefold.




Consider applying for YC's Summer 2025 batch! Applications are open till May 13

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: