You can write object-oriented code in assembly language too. I've done it -- it's fun and it works great. It was well suited for writing video games in the 80s.
Though I agree with Linus' assessment both of the suitability of languages for kernel dev and for his take on C++, I want to point out that it's perfectly possible to write Linux kernel C++ code. The MIT PDOS Click Modular Router team did exactly that; they wrote their own IP forwarding system, down to the ethernet drivers, all kernel-resident, principally in C++. As an LKM.
The Linux people will look at you funny for doing it, but you can in fact write a kernel in C++.
That specific module is what the post was all about. They had to patch up the kernel heavily to get it to compile at all, and surprise surprise, the kernel changed in the meantime and their patches would not work on the later versions. Thus the entire discussion.
Talking to one of my professors, his experience is that if you get deep enough into C++ and use the STL, you get around the same performance as Java. I'm not a big C++ or Java programmer, so I have no first-hand experience, but I found that to be interesting.
I certainly haven't found that to be the case for my routine uses of the STL. Vector iteration, map lookup, applications of the various STL algorithms etc are all very fast in the code in which I've put them to use. Maybe this doesn't hold for more sophisticated uses.
For example, I see no discernible overhead at all in iterating through an std::vector vs a bare C array.
The STL does lead to increased memory consumption and code bloat, however. It is wholly unacceptable to use the STL in any embedded system, or kernel-level OS code.
My experience exactly. The STL==code-bloat argument is really not valid but avoiding STL in smaller embedded systems due to exceptions+new/malloc is reasonable. Once you have a MMU and megabytes of RAM the balance may shift but you still have to worry about realtime behavior.
Right. This is why Ada, which has always paid special attention to the needs of embedded systems, provides so many guarantees about what program behaviors are and are not allowed to cause allocations or exceptions.
The upcoming Ada 2012 standard even includes versions of Ada 2005's collection classes which are allocation-free (read: pre-allocated to a size specified at creation time, and guaranteed not to perform allocation after that point).
Ada's generic programming was a big influence on Stepanov's design of what became the STL (the first versions were a port of work he had done under Ada). Ironically, the Ada standards process moved so slowly that by the time Ada grew standards-mandated generic collection classes (previously this was something all vendors provided as an extension), it had time to learn the lessons of STL.
(Not a knock on STL, by the way -- STL's implementors have learned a lot over the life of the standard as well.)
The key point, IMO is the fact that C++ compilers are essentially a black box, and you cannot guarantee the code that will be output. When you write C code, you pretty much know exactly what the assembly, and thus machine, code will look like (obviously this will vary based upon the compiler optimizations used). This is not true of C++, which is why it is not the most suitable language to write kernel code in. Kernel software is so critical that it is not wise to cede control to a baroque compiler. Especially when C can do everything C++ can (trivia fact: the original C++ compiler was simply a preprocessor that converted the code into C).
I think to call C++ compilers a black box and then turn around and say something like gcc is not is a bit of a stretch, and simply unfair to C++. The largess of the GNU C compiler is the very definition of a black box. If you're going to run off and do loads of systems programming, you're going to have to understand exactly how your black box works. This is still very possible with C++, it's just a lot more complicated given the semantics of the language.
I think this back and forth sort of breaks down because people say things like C and C++ and it's not clear if they're talking about
1) The languages themselves.
2) The compilers
3) Possible runtimes and other overhead that need to be considered in a stereotypical environment (that is, probably not kernel coding). It tweeks me every time we get into a language war, because a lot of the time the language itself isn't the real point of discussion, but rather it's some sideways way of referring to the toolchain that's popular at the given moment. C++ as a language could very well be tooled to write a kernel, given a good compiler and a semantics that coders stick to (just like C). I feel like the C++/HLL camps are crying for something other than C because they're not interested in the super low level details, but still would like to eek some functionality out of the kernel. They're basically saying, "we would prefer tools other than C" (regardless of whether C++ is a worthwhile and better option, I am unconvinced).
I think an even more interesting conversation to have would be: have operating systems kernels become TOO COMPLEX to code in (just) C/ASM? Are we in over our heads? Should we invest in the creation of better tools to handle such large, complex systems or is everything just fine?
DISCLAIMER: I actually don't like programming in C++. I will put up with C, but I usually find myself writing in Ruby or Haskell.
Your point is valid and well taken, but I would like to call out that 1) I specifically mention the use of optimizations as impacting my argument, and 2) I did not mention gcc. I completely agree that for system programming you "have to understand exactly how your black box works," however, I would argue that even if this is technically possible in C++, the cost is prohibitively high. The mapping between C code and machine code is fairly straightforward, /unless obfuscated by compilers and runtimes/.
I fundamentally disagree with the notion that you can write /good/ kernel code in a HLL. A kernel is ALL ABOUT interacting with the hardware and performing low level system management. Sure, you could write kernel code in a HLL, but it is just not going to be as performant as if you wrote the code with "the super low level details" in mind. These are important considerations that compilers do not have insight into. I would go on to argue that to anyone who understood the low level details required to write quality kernel code, those details are not something they wish to overlook. Anyone who doesn't understand those details shouldn't be writing kernel code.
Calling the output of a C++ compiler a black box and saying it's not a good idea to use C++ for that reason, and implying that C is better because you mostly know what the assembly output will be, boils down to an argument against abstraction.
There is a limit to what a hacker can keep in his head at once. You may believe your limit is high, but it does exist. If you eschew abstraction, there is a class of programs you cannot write because you can't keep the complexity managed. This is why it irks me when I see arguments against abstraction - they are short sighted.
Now, there are some perfectly good concrete examples of things C++ compilers do which may not be a good idea in kernel code. For instance, C++ exceptions can cause trouble when the stack alternates between C++ and C frames.
Well, the whole point is that C contains so few abstraction in the first place that most dedicated developers can have a mental model of the mapping between language and machine. There are very few abstractions that don't correlate exactly to machine language in some known way.
C is all about subroutines (functions), jumps (function calls), pointers and quantities that map directly to registers (int, long) — for the most part a fairly thin veneer on top of modern CISC/RISC machine code.
For those abstractions (such as the call stack) that are essentially black boxes, there is the C ABI, which explicitly defines much of the underlying structure.
I remember reading this years ago. It eventually gets into why the Linux kernel isn't written in C++, but the beginning of the discussion starts with an innocent question about how to port a legacy kernel module that was written in C++ for 2.4 and no longer works with 2.6.
The OP is roundly criticized for even considering writing a kernel module in C++. The authors of the module had to patch the Linux kernel heavily to make the headers compile as C++, and of course the patches for 2.4 don't all work for 2.6.
I can agree that if you patch the crap out of an open source project, be it the kernel or just a library, to make it work with your own code, then you get what you deserve when it gets out of sync with the upstream version and no longer is compatible. How could it be otherwise?
But as an experienced C++ hacker I disagree with the argument the C hackers made in the discussion that "you just can't use C++ there, you must use C" (to paraphrase).
The problem isn't that they chose the "wrong" language, it's just that they interfaced the C++ code with the C (kernel) code incorrectly. The Right Way would be to simply write a compatibility layer in C that calls functions in the C++ code. And the C++ code could in turn call back to C functions in the compatibility layer when they need to interface with some kernel data structure. Although performance is listed as an issue, they specifically say that their module gets its performance benefit by not having to copy packet data to user space. They would still get this benefit, even if they had the minuscule extra time it takes to make a call through a C/C++ compatibility layer.
As for optimizations, that is a quality of implementation issue with regards to compilers, not a language issue.
This is a lie.
Because C++ is such a poorly designed language, it is extraordinarily hard to make a (relatively) correct, let alone high performance compiler. Language complexity matters when you're writing a compiler, and C++ is every compiler writer's worst nightmare.
Richard B Johnson rants and makes some poor points. I am more interested in the cultural issues typified by his aggressive behaviour than the technical questions being debated.
26 comments
[ 2.9 ms ] story [ 80.5 ms ] threadExactly. A million times, exactly.
There's a link in here to a book PDF that attempts to teach OO techniques in C. http://www.cs.rit.edu/~ats/books/ooc.pdf
The Linux people will look at you funny for doing it, but you can in fact write a kernel in C++.
http://sourceforge.net/projects/unixlite/
For example, I see no discernible overhead at all in iterating through an std::vector vs a bare C array.
The STL code is highly optimized and there should be no technical reason why it would consume more memory or lead to code bloat.
The upcoming Ada 2012 standard even includes versions of Ada 2005's collection classes which are allocation-free (read: pre-allocated to a size specified at creation time, and guaranteed not to perform allocation after that point).
Ada's generic programming was a big influence on Stepanov's design of what became the STL (the first versions were a port of work he had done under Ada). Ironically, the Ada standards process moved so slowly that by the time Ada grew standards-mandated generic collection classes (previously this was something all vendors provided as an extension), it had time to learn the lessons of STL.
(Not a knock on STL, by the way -- STL's implementors have learned a lot over the life of the standard as well.)
I think this back and forth sort of breaks down because people say things like C and C++ and it's not clear if they're talking about
1) The languages themselves. 2) The compilers 3) Possible runtimes and other overhead that need to be considered in a stereotypical environment (that is, probably not kernel coding). It tweeks me every time we get into a language war, because a lot of the time the language itself isn't the real point of discussion, but rather it's some sideways way of referring to the toolchain that's popular at the given moment. C++ as a language could very well be tooled to write a kernel, given a good compiler and a semantics that coders stick to (just like C). I feel like the C++/HLL camps are crying for something other than C because they're not interested in the super low level details, but still would like to eek some functionality out of the kernel. They're basically saying, "we would prefer tools other than C" (regardless of whether C++ is a worthwhile and better option, I am unconvinced).
I think an even more interesting conversation to have would be: have operating systems kernels become TOO COMPLEX to code in (just) C/ASM? Are we in over our heads? Should we invest in the creation of better tools to handle such large, complex systems or is everything just fine?
DISCLAIMER: I actually don't like programming in C++. I will put up with C, but I usually find myself writing in Ruby or Haskell.
I fundamentally disagree with the notion that you can write /good/ kernel code in a HLL. A kernel is ALL ABOUT interacting with the hardware and performing low level system management. Sure, you could write kernel code in a HLL, but it is just not going to be as performant as if you wrote the code with "the super low level details" in mind. These are important considerations that compilers do not have insight into. I would go on to argue that to anyone who understood the low level details required to write quality kernel code, those details are not something they wish to overlook. Anyone who doesn't understand those details shouldn't be writing kernel code.
There is a limit to what a hacker can keep in his head at once. You may believe your limit is high, but it does exist. If you eschew abstraction, there is a class of programs you cannot write because you can't keep the complexity managed. This is why it irks me when I see arguments against abstraction - they are short sighted.
Now, there are some perfectly good concrete examples of things C++ compilers do which may not be a good idea in kernel code. For instance, C++ exceptions can cause trouble when the stack alternates between C++ and C frames.
C is all about subroutines (functions), jumps (function calls), pointers and quantities that map directly to registers (int, long) — for the most part a fairly thin veneer on top of modern CISC/RISC machine code.
For those abstractions (such as the call stack) that are essentially black boxes, there is the C ABI, which explicitly defines much of the underlying structure.
The OP is roundly criticized for even considering writing a kernel module in C++. The authors of the module had to patch the Linux kernel heavily to make the headers compile as C++, and of course the patches for 2.4 don't all work for 2.6.
I can agree that if you patch the crap out of an open source project, be it the kernel or just a library, to make it work with your own code, then you get what you deserve when it gets out of sync with the upstream version and no longer is compatible. How could it be otherwise?
But as an experienced C++ hacker I disagree with the argument the C hackers made in the discussion that "you just can't use C++ there, you must use C" (to paraphrase).
The problem isn't that they chose the "wrong" language, it's just that they interfaced the C++ code with the C (kernel) code incorrectly. The Right Way would be to simply write a compatibility layer in C that calls functions in the C++ code. And the C++ code could in turn call back to C functions in the compatibility layer when they need to interface with some kernel data structure. Although performance is listed as an issue, they specifically say that their module gets its performance benefit by not having to copy packet data to user space. They would still get this benefit, even if they had the minuscule extra time it takes to make a call through a C/C++ compatibility layer.
Personally I think it doesn't even matter. The kernel is stuck with C, they couldn't port it even if they wanted to.
This is a lie.
Because C++ is such a poorly designed language, it is extraordinarily hard to make a (relatively) correct, let alone high performance compiler. Language complexity matters when you're writing a compiler, and C++ is every compiler writer's worst nightmare.