top | item 1421398

Linus vs C++, again

275 points| hernan7 | 16 years ago |realworldtech.com | reply

199 comments

order
[+] cageface|16 years ago|reply
As I get older and grumpier I tend to appreciate Linus' point of view more and more. It's easy to get swept up by arguments of the expressiveness of a language, particularly in small examples. However, I think in the long run it's better to have very explicit code. The less jumping around and inference I have to do to figure out what a block of code does the more likely it is that I understand it and that I can quickly verify that it does what it needs to do. If that makes code a little more verbose I think it's usually still worth it.
[+] mojuba|16 years ago|reply

   write(fd, buf, size);
Can you list all the caveats, possible side effects, reasons of failure of this simple C function call? Hint: remember, fd can be a file, as well as a NFS-mounted file, pipe, network or local socket, FIFO, device, etc. Hint2: I doubt anyone can give a comprehensive description of the possible consequences of this call.

Bottom line being, C can be incredibly hard to understand, or C++ can be clean, succinct and straightforward. Personally, I'm for the second, although I know probably 99.9% of all existing C++ code is just awful.

[+] martincmartin|16 years ago|reply
How do you explain the success of ActiveRecord? Do you think it's illusory? The exception that proves the rule? Something else?

http://blog.objectmentor.com/articles/2009/07/13/ending-the-...

"The fact that it took decades for the industry to arrive at something as useful as ActiveRecord in Rails is due primarily to the attitude that some language features [in this case, meta-programming] are just too powerful for everyone to use. "

[+] eru|16 years ago|reply
> However, I think in the long run it's better to have very explicit code.

You should love (parts of) Haskell then. You even need to specify whether your code can have any side-effects there.

(Haskell's Type-classes are awfully implicit, on the other hand. Though not nearly as bad as overloading in C++. You do not need to abuse bit-shifting for sending stuff to streams in Haskell. If you want/need to, you can just make up your own new line-noise operator. That new operator won't be used anywhere else, and is thus perfectly grep-able.)

[+] j_baker|16 years ago|reply
As with most things, there are tradeoffs. If the expressive code was written with a good level of abstraction, it should be pretty straightforward to figure out what it does. Of course, it means that you need to understand those abstractions before you understand the code, and you might have to do more jumping around to figure them out. But in the long run, it makes it much easier to remind yourself how certain features work.

On the other hand, you can write obtuse and difficult to understand code in expressive and non-expressive languages. I suppose a point could be made that bad code in say Haskell or Lisp might be worse than bad code in Java.

[+] desponsible|16 years ago|reply
> One of the absolute worst features of C++ is how it makes a lot of things so context-dependent - which just means that when you look at the code, a local view simply seldom gives enough context to know what is going on.

Good point. Very good point.

Having spent few years developing for the Linux kernel I can say that the most cluttered code I dealt with was the network stack. And exactly because it was done in C++-ish way. It makes an extensive use of tables of function pointers, which is basically an analog of a C++ virtual table. A socket depending on its type would get a pointer to a different table and that table would define the actual flow, say, of the recv() call in the kernel. The concept is very elegant, and it translates into a more compact code, but it also makes tracing the code by hand hard.

So, yeah, Linus got a point there :)

[+] stcredzero|16 years ago|reply
I started designing a language where you had lexically scoped "contexts" to specify the meanings of words. In general a package/library would be a context, and could declare its dependency on other contexts. Any words with conflicting interpretations would have to use its full global specifier to compile.
[+] jrockway|16 years ago|reply
Actually, you refute his point. If they were actual classes instead of ad-hoc vtables, the flow would be clear.
[+] mikeklaas|16 years ago|reply
I think your example proves that it is how features are used, not the mere fact of the possibility for use in a language, that creates the problems linus refers to.
[+] johnrob|16 years ago|reply
I think Linus is making the right call here. At a 10,000 foot view, the real argument is about style. The style of C happens to be one that lends itself to easier groking of code amongst hundreds of developers (as he illustrated well). Sure, C++ may be a more modern tool with some more powerful features, but using it may not be the best thing organizationally.

This kind of thinking is refreshing and is seemingly rare in classrooms. There, you mostly learn 'what to use' and not 'how to determine what you need'. Just as I'd expect, over design is the most consistent issue I come across in co-workers' code. 'Write code to be read' is a metric that seems to have gone out of style. Code that does X-Z-Y should, in my opinion, look like code that does X-Y-Z. Otherwise the reader has to invest time and energy figuring out the design. There had better be a good reason to justify a hard-to-grok design, because it will continue to be a drain for the life of the project.

[+] j_baker|16 years ago|reply
I actually rather like this quote:

    Anybody can say "yes". Somebody needs to say "no"
[+] ecaradec|16 years ago|reply
it's interesting to note that open source works in reverse of entreprise where any manager can say no, but only the boss can say yes...
[+] c00p3r|16 years ago|reply
It corresponds to Brooks's idea (law?) that one architect (with view) is good, while many is a disaster.
[+] rpledge|16 years ago|reply
Linus has a touch of what I think makes Steve Jobs great: the ability to say no and stick by those convictions. No argument from me that Linux is wildly successful and one of the most important tech developments in the last 10 years.

However, I always cringe when I read some of his comments that seem to reject any element of forward progress. While C++ certainly has its share of issues, Linux will never evolve if the programming paradigm stays in the 60s. My gut feel is there is a lot of opportunity to do better over the next ten years.

[+] hristov|16 years ago|reply
It is very silly to say that something is bad because it started a long time ago. I do not see how any of the modern languages of the 21th century would be even remotely suitable to write an OS kernel with. Considering that most of those languages are at least partially interpreted and require GCs, a kernel written in them would be painfully slow.

Just because something is old does not mean it is worse, and just because something is new it does not mean it is better.

If you think about it, the modern languages are clearly made for programming higher on the stack (i.e., at application level). That makes a lot of sense. After all most programming is done at the application level, and it would make sense to write a language that makes that type of programming easier. And of course many modern languages are very successful in that respect. But it is silly to assume that just because they are successful at the application level they would make good kernel programming languages.

The reason why C++ is the language being considered is that it is also a relatively low level language which means that it can potentially replace C for kernel level programming. That of course does not mean that it should, and Linus does a good job of pointing out the issues with C++.

[+] dman|16 years ago|reply
From linus's post - "And the best way to avoid communication is to have some "culture" - which is just another way to say "collection of rules that don't even need to be written down/spoken, since people are aware of it". Sure, we obviously have a lot of documentation about how things are supposed to be done, but exactly as with any regular human culture, documentationis kind of secondary." He seems to suggest that sticking C keeps the focus on attracting people who like to build things. There are surely very productive programmers who use c++ and other newer languages but sometimes embracing new developments means opening the door to people who are just following fads. Just as an example - the kernel has managed to avoid the following developments - uml, xml etc. Not saying that uml and xml dont have their legitimate uses, but sometimes keeping things bare and simple has the effect of keeping posers out. As a sidenote, I dont seem to recollect any recent groundbreaking progress in languages for systems level programming (singularity from microsoft might be an exception). At some point people were trying things like oberon, lisp machines, but I dont seem to recall any new developments which explore dynamically different ways of building computer systems. For better or for worse we seem to have settled on a local optima of c and unix based systems.
[+] wvenable|16 years ago|reply
I'd like to see Linus tackle a systems programming language now that he's tackled version control. I'd think that would be entirely within his domain.

But C++ is not the answer here. It wants to be all things to everyone (low-level, high-level, object-oriented, functional, etc, etc) and is therefore useful for almost every kind of project but well matched to none of them.

[+] fleitz|16 years ago|reply
Linux is FOSS, so if there are huge benefits to using C++ then the people who advocate such things should simply take the tree, fork it and start doing some C++ stuff. If their arguments are correct it should soon be fantastic and much better than Linux.

Also, there is nothing wrong with programming paradigms from the 60s as evidenced by the popularity of Clojure and other functional languages that borrow heavily from LISP.

[+] yonilevy|16 years ago|reply
Well, he did create git. Not that your point isn't valid, just pointing out Linus is actively helping forward progress.
[+] jrockway|16 years ago|reply
If C is 1960, C++ is 1961. It'd be nice to join the 21st century, or even 1980.
[+] jafl5272|16 years ago|reply
He's not rejecting progress. He explicitly says that C isn't for everything. But he wants real progress: a language with GC, concurrency, etc., not just C-with-classes-plus-etc-etc-etc
[+] forgottenpaswrd|16 years ago|reply
It is actually good as it is, like scientific progress, if someone wants to make a new kernel in .NET or Lisp, he could fork it and prove is better that way. But please don't force everybody to follow you.

MS created Vista using 2000s paradigm. It was slow as a snail.

Experiments could fail too.

[+] desponsible|16 years ago|reply
> Linux will never evolve

Do you terribly mind elaborating on this rather bold statement?

[+] xpaulbettsx|16 years ago|reply
Let's put it this way without any subjectivity: every production kernel that you folks use every day is written in C. NT is, Solaris is, Darwin is, and Linux is.

Not one production-level kernel that is in wide use as a general-purpose operating system uses C++. I don't believe that to be a coincidence.

(Nitpicker's corner: Darwin's device tree subsystem is written in Embedded C++, an extremely cut-down version of C++ that's more like "C with classes" than C++).

[+] shin_lao|16 years ago|reply
That's perhaps because all these kernels were written before C++ exists? The first C++ standard is from 1998, and stable STL/C++ support is even more recent.

FYI : in NT many device drivers are written in C++

[+] dman|16 years ago|reply
I actually liked his point about context very much. In fast moving projects changes are visualised in terms of diffs, and the closer the code is to what will be executed, the more chances that obvious flaws will be caught. btw related discussion in an older thread - http://news.ycombinator.com/item?id=1318489
[+] huherto|16 years ago|reply
It is funny how a very simple and innocent looking question by "newbie" started a big discussion. It is like watching somebody drop a candle in a bed.

    Can you use C++ in Linux kernel?
    In windows kernel you can, with some restrictions.
[+] viraptor|16 years ago|reply
What are the chances he's just a troll? A simple google search would show many similar debates.

I'm pretty sure you could cause the same in a month or two, by asking "I know there are projects using different languages to create kernel modules - even crazy ones like haskell. Can I use C++ in the kernel?"

[+] Daramarak|16 years ago|reply
Yes, but it is good to have such debates. It allows the Linux community continuously to reassess its choice of a c-only environment. Such introspection is necessary, and when people are ready to move on, I think the community will.
[+] yonilevy|16 years ago|reply
There's not much "Linus vs C++" in there (except for several random bashes with nothing to back them up). It's mostly Linus sharing his POV as the maintainer of the kernel as to why C++ would be harder to work with in a project that has many contributors due to code being more context dependent (i.e member functions, function overloading).
[+] shin_lao|16 years ago|reply
There are so many large scale C++ projects that prove Linus wrong every day. One of them, you probably use it every day. hint: it's a search engine.

Whatever language you use, you need rigor and diligence. You need to manage the project and follow up on developers.

You need to agree on a subset of the language, that will become your local dialect. I'm pretty sure that Linus doesn't accept "any C source code".

C++ has got more features than C. That's neither intrinsically good or bad.

I could argue about the merits of templates and what they enable you to do, and someone would tell me "it's hard to understand".

Well, any language you don't know is "hard to understand". C++ is not "C with classes" anymore. It's something else. It's a different language.

In the end what really matters is the quality of the developers and the quality of your process. The language is just how you implement your concepts.

[+] eps|16 years ago|reply
Main problem with C++ is non-technical. Based on some experience interviewing a dozen people a week for several months, C++ programmers tend to routinely overestimate their proficiency with the language, while C programers tend to have the opposite self-assessment. To put it differently - on average C++ devs are cocky, eveyone is a guru and C devs are basically modest.
[+] kensan|16 years ago|reply
I would inject into your list of what really matters something Linus said: communication. Having each member of the team (1000 contributors to the kernel by Linus's estimation) in a different corner of the world is a huge consideration.
[+] sliverstorm|16 years ago|reply
This leaves me with a burning curiosity.

Linus, if you could change the Linux kernel to another language, would you?

In a perfect world (i.e. migration concerns and such aside), if you were changing the Linux kernel to another language, what language would you choose? If you feel C is still the #1 choice, what would the #2 choice be?

[+] huherto|16 years ago|reply
I would like to hear Linus opinion on Go.
[+] ecaradec|16 years ago|reply
Wow, Linus is getting older : he didn't flame the poor guy down.

I feel a bit concern that Linus don't write code anymore but still decide on how code is written, etc... Happily, he has some experience.

Linus has good reasons, nobody is going to rewrite linux in C++ anyway, this has been debated to death.

Why I am still loosing my time commenting on this ?

[+] dan00|16 years ago|reply
It's right, that in theory I can't know what a C++ function call means.

But that's also the case for C. In C I can assign a function pointer to a variable. When the function is called through the variable, than I don't know which function is called.

Almost never the language is the problem, but their usage. There's always context, and the quantity depends mostly on the complexity of the software. And regardless which language you use, you have to define a convention for the usage of the language, also in C.

[+] shoover|16 years ago|reply
Interesting point about function pointers. Maybe Linus is saying (in many more words) to use virtual dispatch only in appropriate places but not as a basis for an entire language? He would be in disagreement with every language designer who has added some kind of first class dispatch or pluggable modules. Not that such disagreement would be surprising, but that seems to be what he's saying. He suggested looking to other languages for GC and concurrency support, but in that thread I didn't see any desire for dispatch or modularity beyond what C offers.
[+] d0m|16 years ago|reply
I've seen some pretty clean C++ code and some ugly C code. I think what's important is how a programmer use a language rather than what language he uses. I mean, if someone enjoy writing clever one liners, he/she will probably do it in all languages, might it be Perl or C. However, the important point here is that C does a good job and the programmers are used to it and like it. THEY, people that submit patches, like it, period.
[+] snorkel|16 years ago|reply
Even if the Linux kernel were rewritten in Erlang and it won't change the fact the vast majority of *NIX systems level code is entrenched in C. The most popular LAMP stack ingredients are also written in C. Face it; it's a good language.
[+] eru|16 years ago|reply
Non sequitur?
[+] mkramlich|16 years ago|reply
Regarding C and C++ I sometimes think of them like this:

If you want a language that's like C but better, tough, just use C.

If you want a language that is better than C, do not use C++.

[+] pmjordan|16 years ago|reply
It makes a lot of sense if you think about it as optimising code readability for the case of seeing it through the lens of

  diff -pu -c 3
which is basically what Linus does all day. This also implies that the argument has little meaning in the context of projects that aren't comparable in scale (both code size and contributor pool size).
[+] matthavener|16 years ago|reply
Could Linux explain spinlock.h then? Depending on which type you give to the PICK_OP macro, it performs a different operation. Its basically a C template. Seems a bit weird to complain about type context specific code and then use it in one of the most important parts of the kernel..

Here's the code: #define TYPE_EQUAL(lock, type) \ __builtin_types_compatible_p(typeof(lock), type )

#define PICK_OP(op, lock) \ do { \ if (TYPE_EQUAL((lock), raw_spinlock_t)) \ __spin##op((raw_spinlock_t )(lock)); \ else if (TYPE_EQUAL(lock, spinlock_t)) \ _spin##op((spinlock_t *)(lock)); \ else __bad_spinlock_type(); \ } while (0)

[+] jheriko|16 years ago|reply
"And the best way to avoid communication is to have some "culture" - which is just another way to say "collection of rules that don't even need to be written down/spoken, since people are aware of it". Sure, we obviously have a lot of documentation about how things are supposed to be done, but exactly as with any regular human culture, documentation is kind of secondary."

This is so true - I have zero problems with context sensitivity and difficulty reading C++ if its all consistently done according to my prefered standards (which I mostly inherited from an especially well managed employer), avoiding the "bad practices" that introduce these problems like namespaces and such. Yet if I dive into some poorly organised and written code I can easily spend a whole day debugging a trivial problem - simply because the time is wasted trying to understand what is happening.

The sad truth is that the latter case is more common - its not C++'s fault though (although it could just /not/ try and provide every imaginable feature) - its more bad management than anything else. Though I can't help but wonder if that is just unavoidable for inherently difficult to manage projects like this...

[+] albertzeyer|16 years ago|reply
Many of the arguments he gave are mostly just based on the fact that there aren't that much powerful tools around which can do what he requests (and what of course is something you want to have).

Like grepping for all usages of some function. Or getting some code snippet in a way that it comes with all necessary context. Or whatever.

Though, with recent development (particularly on clang), these things may become much more easier. Of course, you will not be able to do magic things (like checking at what places what particular virtual function implementation is called exactly) but it will be trivial to check for example all calls on std::string::size etc.

In the same way, you could also implement some small helper tool for sharing code snippets which will add some meta information about the context. So that when you share some code like 'a += "foo";' it will contain the meta information that a is an std::string.

LLVM/clang is anyway also kind of a disprove to his arguments about maintainability. I would say that one reason that working on/with the LLVM/clang code is so much nicer compared to working on/with the GCC code is because it is written in C++.

[+] acqq|16 years ago|reply
You're wrong. I've actually had to maintain the big C++ projects. That have Zillion of classes, fully different, but each one has more Read(), Write() functions. Some are virtual, some are not. Some have two parameters, some have three, some four. And they even do fully different stuff! Which Read() will be called depends on anything and everything. I claim you just can't figure out what some piece of code does in any other way than by actually single-stepping through the debug build. Any time the debug build pieces of code don't reflect the source, you're fully lost. Note that Linus usage scenario is "read the chunk of code outside of the whole source base" and you argumenting "if I use some hypotetical very clever tool the tool would maybe able to show me what some line in the chunk of code actually does." I've actually made some "very clever tools" since some twenty years ago. And I wouldn't want to have to use them on the really big projects.