Linus Torvalds on C++
harmful.cat-v.org
harmful.cat-v.org
I much prefer C when writing systems-level code. It's simpler and a lot more predictable. You don't get the illusion that things like memory management are free.
I /have/ written drivers in C++. Here you have to be very careful about memory allocation (calling 'new' in an interrupt handler is usually death, though I've also written very specialized allocators that work in IRQ contexts). STL isn't going to cut it, especially if you're writing something real-time that needs very predictable performance.
So, my basic prejudice is that while you can use C++ for systems stuff, you still really need to be close to C semantics, so you're basically buying namespaces and "C with classes" at the risk that some yahoo later on is going to #include <map> and utterly hose things . . .
Issues of real-time performance and new vs malloc vs in-place/nothrow new also seem like orthogonal concerns here. The larger problem is that yahoo who's using the wrong algorithm and/or maintaining driver code w/o benefit of code review ;)
C++ code just tends to assume it's fine to do whatever crazy stuff it assumes needs to be done, like allocating 4 bytes at a time using new. C code is usually more careful about that, and quite a few packages offer control of their memory allocation in C. (Yes, C++ does allow you to overload new and delete, and have allocator traits, and more. Come back when you've actually implemented this for a library you did not write, and we'll discuss war stories if I can remember them. It was 2001, it was ugly back then, and I'd be surprised if it is better looking now).
The argument "let's use a castrated language to avoid mistakes" falls short. What about communication within the team?
Properly used and tailored, the STL is extremely adequate to kernel development. The power of the template engine enables the compiler to do some very clever optimizations.
More information: http://www.osronline.com/article.cfm?article=490
In any case, kernel guys seem to prefer their data structures in intrusive style rather than the container style ubiquitous throughout the C++ standard library. (For an example, see the intrusive list and red-black tree implementations in the Linux kernel.) Intrusive structures allow for exactly the kind of low allocation, very memory friendly layout that kernel developers are looking for - no clever optimisations necessary.
C++ features like stronger type checking, more careful casts and RAII are a more compelling argument for the language.
This makes it easier to package up code into modules, since you can have namespace foo { bar } and namespace baz { bar }, without worrying that the two bar symbols will collide.
For me, the biggest argument against C++ is that programmers can make much better use of their time than learning the massive list of quirks in C++ compilers. Having more features is not a deal breaker per se, even if it does cater to messy code. In real world situations you can usually choose a compiler for the whole team and a style for the whole team. This works in my company. But you have to be aware that this doesn't have to work in all situations, or even most situations.
With inline functions and dynamic variable declarations already in C99, I really think the complexity/usefulness compromise of adding anything else that is also available in C++ is very, very negative.
For other higher level features there are many other languages I'd take over C++. Ruby, LISP, Python, even Java or C# if you're that fond of C-ish syntax. For low-level stuff and speed, nothing higher level than what I said above. In my team C++ is nobody's favourite language but it's still what we use the most. Sadly, there are many other factors other than personal preference.
Would you mind expanding on how you set things up and what you do to use m4?
In m4 I simply created some sort of preprocessor that renamed variables to have some sort of prefix depending on namespace. I haven't used this for a good while because then I have the issue that MSVC doesn't support other modern C99 things that I consider basic unless you compile in C++ mode, thus negating this. At work I need MSVC compatibility...
Hope you get to read this.
If I were to do this again today, I'd use OMeta. Give it a look, it's dead simple if you have the time to read through it.
To object against C++ with the argument that incompetent coders can do bad things... well, it's nonsense. Incompetent coders can do bad things in ANY language. For competentt coders thugh, C++ means increased productivity and resusability, and in the end, that's what counts.
You're about twelve years outdated: https://en.wikipedia.org/wiki/C99
Anyway, Linus may be a very experienced C programmer, but that doesn't mean his opinion on C++ carries much weight... I'd be more interested on what someone who actually has a lot of experience in using C++ says. Especially with modern C++ and recent tools, libraries etc, which are very different from what was around five or ten years ago.
I suppose it is nice for a change for someone bagging out C++ (however inaccurately) to be advocating C instead of a managed or interpreted language though!
It does make me wonder though how he's able to get away with responses like that, when most other "founders" (not sure what the proper term here really is) would have the majority of their users/supporters just go elsewhere.
EDIT: ... Let alone have supporters who get defensive enough to start downvoting someone who stated the obvious (he did act like an ass), while asking a reasonable question too.
I've read Torvalds' post at the top of the page. I've also read the balance of opinion on this page. The majority view is that C++ really is a terrible language for writing a kernel. Fine, I accept that.
Now re-read Torvalds' post. How many people here would want to work with someone who regularly expresses himself like that? I know, I know; substance is more important than image and so forth. But that post reminds me of what people said working with Steve Jobs was like before he died.
Life is too short to work with jerks.
EDIT: Removed excess snark.
Sometimes, he's quite the opposite of a jerk [1]:
WARNING! I wasn't kidding when I said that I've done this by reading
gtk2 tutorials as I've gone along. If somebody is more comfortable with
gtk, feel free to send me (signed-off) patches.
Just as an example of the extreme hackiness of the code, I don't even
bother connecting a signal for the "somebody edited the dive info"
cases. I just save/restore the dive info every single time you switch
dives. Christ! That's truly lame.
One must remember that his role as maintainer of linux requires him to have ultimate, non-ambiguous opinion about a lot of stuff. He's the judge of what effectively goes into the "official" kernel tree. Moreover, most of the kernel contributors don't deal with him directly — git is the materialization of that modus operandi.When he does express himself like that, however, it becomes news. He always has a reason, though. In this case:
Please don't talk about portability, it's BS.
Is this how normal people start a conversation? Who's the jerk, here?[1]: https://github.com/torvalds/subsurface/blob/master/README#L1...
The man delivers.
"for something where efficiency was a primary objective the "advantages" of C++ is just a huge mistake. The fact that we also piss off people who cannot see that is just a big additional advantage."
I don't know if it's intentional or not but many OSS project leads respond like this to questions that come up a lot but don't merit a response. How many times do you think Torvalds has had to field "questions" of the form "C is crap, you should use C++, it's like C only better!"
To a certain extent it is garbage in, garbage out, if you ask a stupid question, you get a stupid answer.
Come on. Dude was picking a fight, and he got it. Maybe there are other examples of Linus being an ass, but I don't see how this qualifies.
I have considerable experience with C++, going back to when it was called C with Classes and you used a preprocessor to convert C with Classes code to C and then compiled the C.
What Linus says is pretty much true. I don't expect it to matter though since when people say "I'd be more interested on what someone who actually has a lot of experience in using C++ says." they don't really mean it.
There is another guy I know of with considerable experience in C++, Yossi Kreinin, who knows more about C++ than Stroustrop. He has a very nice web site that is one of the best references in C++ I have seen, going far deeper than others. Yossi is the number one expert on C++ in the world today. I recommend his insights to all: http://yosefk.com/c++fqa/
So what's his excuse? RE: Linux
I got about 3 pages into the meat of the FQA. I can't bring myself to spend the time to go further, because his counterpoints already seem overwhelmingly specious to me. This leads me to wonder on what grounds you characterize him as "the number one expert on C++" "who knows more about C++ than Stroustrup".
The best reference on C++ that I have seen remains the C++ FAQ. (http://www.parashift.com/c++-faq-lite/) I have also always enjoyed Stroustrup's guidance on his language, and I'm inclined to continue believing he knows at least as much about his own language as anybody, until I see some more convincing evidence to the contrary.
Now with the new C++ there's a ton of new stuff to absorb.
Take inconsistencies for instance. An inconsistency between two things means that one but not the other can be inferred by applying a particular principle. But who chooses the principle that is applied to decide whether or not there is an inconsistency?
There is no shortage of "principles" in people's heads, many of which are not at all formal, maybe not even explicitly stated and they might not be called principles at all. They may be complex webs of associations, habits, or patterns that apply in some but not in other application areas.
Another such thing is the balance between generality and special casing. You could probably find out empirically what level of either is outside of what most people can use productively. But no individual is most people. So everyone has to decide what makes them personally productive.
The only regrettable thing is that so few people even try to find out.
Irrespective, I don't doubt that C is a valid and perhaps better choice for writing an OS kernel. There's less abstraction in C, and you have to worry less about making sure you don't use a language feature of C++ that has a hidden cost.
https://github.com/mtrencseni/quake3
The book I mentioned, "Large Scale C++ Software Design":
http://www.amazon.com/Large-Scale-Software-Design-John-Lakos...
I don't like C++, but I like C.
Counterintuitively I think the underlying reason is that C++ follows the exact same philosophy as C. For all of the following statements you can replace C with C++ and it is equally true:
Every feature X acts in such a way to make implementing it at the time of its invention as expedient as possible
The best heuristic for guessing how a feature you don't know (or forgot) works in X is to say "let's imagine X was just as it is now, only without this feature, how would I implement it?"
All of this means that in order to be a competent X programmer, one ought to be able to write an X compiler without too much outside help.
I could go on and on like this, but hopefully you get the point. Now it is clear that the philosophy for X works for small languages (like C) but could easily have scaling problems (like C++).
It also becomes clear why so many places subset C++, but don't pick the same subset. The problem isn't that some feature is broken, the problem is that there are too many features without an overriding rule that most people can apply. I would also believe that Bjarne Stroustrup can be quite effective programming C++ since he knows the language intimately enough.
There are plenty of applications for which c++ is a perfectly sensible language choice. Git isn't one of them.
This description sounds like an excellent language for git to me. And in fact, while I don't like C++ much in general, if properly managed, I think a project like git could do well if written in C++.
What it's intended to do is rather different than what it's actually used for in real life..... code talks, anything else is just smoke, right?
IF someone can come alnog and show us a better way in any language, then tehre's something to argue about, otehrwise, the guy who has working code wins over the guy without it, always.
The problem is not so much that C++ is a worse language than C - it's that it makes it insanely easy to shoot yourself in the foot in hideously complex ways that take forever to unravel. See e.g. two phase name lookup - http://blog.llvm.org/2009/12/dreaded-two-phase-name-lookup.h...
There are plenty of other places where the design constraints of C++ have forced it into a dark corner on the edge of the realm of madness. It _does_ buy you additional abstraction, but there is a price you pay for that.
Personally, I'm not happy with either camp. C shows its age - it's from the 70s - and C++ is just out of control. So I'll continue to use both unless there's a decent replacement. (I'm squinting at Go, Rust, and BitC - and none of them are quite what I'd like to see)
It's true that most people don't need the performance you can get with C++ but if you do it's still really your only serious option.
The API of that library, though, is pure C.
To write new code, C++ can be very clean, and C++11 is a huge step in the right direction for this. But to maintain code, especially code written by someone else, C++ can be a little bit hard. And it can never be easier than maintaining C code, because maintaining C code is a subset of maintaining C++ code.
It's pretty important to have good automation for the C-to-high-level conversion, for example GNOME has a gobject-introspection to do this, and Firefox has XPCOM. Otherwise it becomes too tedious and bug-prone to be gluing two languages together by hand all the time.
An old blog post http://blog.ometer.com/2008/08/25/embeddable-languages/
I suppose node.js could be considered another example of this approach, by writing the super-tiny-and-fast event loop and http parser in C and then putting all the application logic in JavaScript.
I wish Linus had added more detail. Is the complaint that the binaries are too big (not quite, if you strip them of the unnecessary symbols) ? or is it that it can be a tedium to go over the reams of error messages that compilers spit out when things go wrong. The second point I am willing to concede, it requires you to read messages inside out, which lisp does train you into doing. Or is the complaint about something else entirely ?
Something else that I hear often that bothers me is the claim that STL adds huge runtime overhead. Maybe it was true with the old compilers, but with the current ones, GCC4.5, Intel its not true at least not in a noticeable way. The whole point of STL was the ability to generate optimized code. I have actually verified that the iterator based access patterns on vectors for instance gets optimized away into simple pointer based indexing into memory blocks.
I like STL, in fact I will go so far and admit that I will not code in C++ unless I sense that I will benefit from STL and or templates. Though STL gets used often merely as a container library I think you get more out of it when you use its algorithms. I really like it that I do not have to write for loops (and potentially get the indexing wrong).
If one squints the right way, it has map, reduce, filter and map-reduce all built in (transform, accumulate, innerproduct) though I miss a vararg zip function. An un-ignorable side benefit to using the STL primitives is that if a parallelized version comes along the way, you get a fairly painless way to make your code parallel. You do have force some of your snippets to be sequential to account for the fact that there is not enough work to parallelize. This is the direction were GCC's STL library is headed with its parallel_mode. http://gcc.gnu.org/onlinedocs/libstdc++/manual/parallel_mode...
@cube Appreciate your comment. For writing kernels and VMs I gladly buy your argument, to add to what you said there is the ABI mess.
One is due to it's completely generalized nature. Since it's not heavily optimized for either speed or memory use, it tends to perform rather poorly in both areas. Not that acceptable when you're making kernel code, where it's often better to write optimized data structures for the problem at hand rather than just relying on templated code. In that situation, where performance is king, you want to tailor your data structures to fix your problems, rather than the other way around.
STLPort and Boost fare better in this respect, but STLPort in particular leads to the second problem.
The second problem is due to the std namespace. Using the std namespace means things that link in your code, even dynamically, cannot necessarily use other STL implementations. So if the kernel uses STLPort, that means that every other program written on top of the kernel needs to use it.
The Linux module API/ABI has worse problems than that already.
Please explain to me how this would fix anything? ;)
In C, in order to string several data items into a collection one would add a container-specific control element to the data item, and then feed a pointer to this element to the container code. Container sees only these elements, and nothing else. On one hand, accessing actual data item obviously requires casting and offsetof'ing, but on other hand it allows placing the same data item into multiple containers, and this is great. Think - multiple key-value stores, each keyed by a different field in data item. Generally speaking, the paradigm is that there are THE data items, and there are miscellaneous supporting structures that help organizing tehm.
In C++, container is the ultimate destination for a piece of data. It is the owner of a data item. If I want a piece of data to be on a list and in a tree, I must decide which will be the "primary" container. Alternatively, I can store a pointer to an item, but this effectively negates safety benefits of STL containers.
http://www.boost.org/doc/libs/1_47_0/doc/html/intrusive.html
Not that most of what you said isn't true. Just picking the nit that 'the container owns the data' holds only for the STL, not C++ in general.
You can have a container of smart pointers, too, if you really don't want to think about ownership.
Another angle to consider is this - if container control elements (like list_head) are stored in the actual data items, they are effectively pre-allocated, meaning that inserting an item into the container involves no heap activity, and this helps simplifying the (error handling) code quite a bit. I mean... all in all, even it seems hacky, it is a more elegant idea. STL to C-style containers is what Java is to C++ - something with all fun drained from it :)
http://www.boost.org/doc/libs/1_47_0/doc/html/intrusive/intr...
Since you can write C in C++ of course everything can be written in C++ too if you don't use C++ "common" libraries and roll your own infrastructure. Once you care about "guts" of your program enough that you have to care about allocations, you'd see that as soon as you're thinking about "containers" having "pointers" to "objects" you're probably on the wrong way. Because "objects" often contain pointers that make part of more data structures but also can be of different size (you can't even "sizeof" them) and also you want to be the one who controls when and where each of them is actually stored (in a sense of the memory block).
I've done these things in C++ without boost, more "in a C way" inside of the separate modules (those that were critical) and I still wouldn't use boost monster, the amount of code dependency is much smaller that way.
Also see groby_b's: http://news.ycombinator.com/item?id=3641890
Essentially, listing all the hoops EA went through to have a useable STL for games. (And for programming purposes, AAA console games and OS kernels are pretty close)
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n185...
I'd still like to see how both these papers influenced last C++ standard at the end (I admit I didn't try to follow) -- is there finally a "standard" way to do all that?
But I blame them when they insist that what they do is enough for everybody. It isn't.
As for the Lakos allocator model, two issues come up:
(1) You get an allocator pointer in everything.
(2) Each allocator still doesn't get to be simple: if the container passes the allocator down to its elements, the allocator has to worry about very differently-sized allocations. E.g. rb-tree nodes and the contained types.
On one hand, it's not particularly good for really low level coding, as other people have explained.
But on the other hand, it's not really convenient for higher level coding, either.
To see what I mean, compare the interfaces of std::string [1] and Qt's QString [2]. Common, simple things like converting numeric data to/from string, splitting into substrings, and find/replace are a PITA in the STL. The containers are nice, but even they could use some work.
I know it'd never happen, but I think the non-GUI parts of Qt would make a really nice standard library.
[1] http://www.cplusplus.com/reference/string/string/ [2] http://developer.qt.nokia.com/doc/qt-4.8/qstring.html
Git compiles on lots of (arcane and ancient) Unix flavors, and has to deal with the compilers on those platforms. C is still the right choice for git.
Oh, is that why Git has such great support for Windows?...
...
Willing to specifically support archaic but important systems who desperately needs git (idk, NASA supercomputers perhaps?) is fine, but that's kind of a niche strategy; it's not about portability anymore.
Linux kernel developers tend to like making sure the Linux kernel works on as many obscure architectures as possible. See https://en.wikipedia.org/wiki/List_of_Linux_supported_archit...
Making sure Git is portable across system architectures is quite important.
Also, portability in the "being available to many systems" thing is important for a lot of developers. I build stuff that currently has to deploy on SPARC/Solaris, but there are plans to make it so that in the not-so-distant future, all that stuff will be moving to virtualized clusters of x86_64 Linux. Portability in the narrow UNIX sense is pretty damn important to a lot of people.
Of course portability is pretty damn important : it gives you the liberty to choose the system you want (depending on your needs) while keeping the same user experience everywhere. But x86_64 Linux systems (for instance) should not be supported because they run Linux : they should be supported because a whole bunch of people use them and need that support.
It was basically C with encapsulation. So using C++ as a better C.
It worked well. It didn't use STL nor boost and the exceptions weren't as you'd know them. Memory management was much more carefully counted than is normal in C/C++ programs, and reservation meant commit.
It was programmed by a pretty clever disciplined bunch. Well, most of us were ;)
If you're going to ask me if I had worked on any OS kernels or distributed version control systems, the answer is no. But I would also never degrade people who might otherwise be willing to help contribute to my projects based on some idiotic notion of programming language superiority.
At this point I don't even expect anything better out of him because he did something great for the world. I expect better just because at this age he should be an adult.
Probably Linus is right that C++ does not belong in the kernel but for application level code reinventing all the basic C++ things in C seems like a waste of time. Linked lists, virtual methods, some form of exception handling.. why waste your time? I laughed pretty hard when I understood how the linked list implementation in the Linux kernel works (pointer arithmetic tricks + sizeof). People don't even invent anything different from whats already in C++.
The key to using C++ is to find a comfortable subset and stick with it. I haven't used C++ on projects with more than 3 people yet so I don't know the pains of agreeing on exactly which subset to use but I imagine it could be done.
I've seen a lot of people use inheritance to save keystrokes. "I can save time if Plane inherits from Bus, they've both got wheels, after all." That's a kind of "typing" system . . . but not the kind that people expect :-)
Honestly, the world does not often cleanly decompose into a class tree. Usually it's pretty messy.
"C++ is a complex language, and if you don't learn it properly, it's very easy to shoot yourself in the foot. And that is also why you shouldn't listen to most non-C++ programmers hate towards C++. Most of the time, they didn't learn the language properly, so they're not really able to judge the language"
What does that mean? It sounds like, that without some significant amount of knowledge, you can't understand it's benefits.
Thinking of the languages I know, I think the things they are trying to improve are apparent with a basic knowledge of the language.
That being said I use some features of C++ I like (inheritance and STL) and while the result is somewhat bastard C/C++ it does what I need well, which at the end of the day is all we should really ask for from a language.
STL and Boost may not make sense for the kernel, but there's nothing wrong with using C++ classes at their most basic. The kernel would be far more readable if it used classes and simple inheritance rather than re-inventing the wheel with structs full of function pointers.
C++ gives you more flexibility with regard to encapsulation as well - it's hard to argue that that doesn't lead to cleaner, safer code.
I think you got that backwards. Structs full of function pointers predate c++. Going for the ad absurdum, why bother inventing C++, it's just a re-inventing of the structs full of function pointers wheel?
Basically, those who don't have access to basic object-orientation are doomed to implement it themselves in a messier, more verbose form.
I, on the other hand, would argue that C's lack of object-orientation somehow dooms one to implement it. OOP is _not_ the pinacle of software development. Further, I would argue that "structs full of function pointers" neither, necessarily, represents a desire for object-orientation nor is it messy.
struct obj
{
struct obj_functions* functions;
...
}
struct obj_functions
{
void (*do_something_with_object)(struct object* obj,...);
...
}
... I'd say it's hard to argue that you're not implementing C++ style OOP, and that it wouldn't be cleaner to use C++.Now, if you're just going to stick to the basics of C++ (ie. avoid templates, operator overloading, etc...), then there's a fair argument as to whether it's worthwhile. Certainly it's not worth rewriting the Linux kernel at this point.
But, I don't think Linus's comment that "C++ is a horrible language" is fair.
(I'm sure most of that is just Linus being Linus).
The experiment didn't last long.
"The changes to get linux to compile with C++ were very minor, so if your extensions are well-written, it should be no problem at all getting it working. Gcc gives reasonably good error messages anyway, so you can usually just try to compile the old code and fix the problems as they crop up.
Linus "Bad programming is language agnostic. Disliking a language generally implies that you don't know enough about it to really get it.
I mean, MongoDB, Node.js, Microsoft's Windows Runtime (which provides access to the systems API for both JavaScript, C#/VB.NET and C++), MySQL, Membase, Haiku, Chromium are all notable examples of software written in C++ that seems to be quite well.
Every time I conclude that all I'd gain in the process is the extra work of finding some third party collection library, adding manual resource management where I currently use RAII, and rolling my own struct-based object system, probably with a buch of macro glue.
I don't see how this makes my life any simpler.
Also Darcs was written in Haskell and Bazaar with Python.
I hate C++ too (over 10 years of experience). But Linus is full of BS too.
Yes, choice of C language in Git is right choice. But source code of Git is horrible and unmaintainable mess.
Then, the BSD guys would have even more reason to call Linux garbage and the OS/language/superiority wars would rage on for even more generations. Wouldn't that be so cool.
edit: I didn't see the last part of your comment, did you edit it? either that or I have a sense of humor failure :)
IMO Objective C gets much farther in implementing polymorphism and dynamic binding than C++ can even dream of.
Although I hear good things about Boost, I think thats like patching the language instead of fixing the fundamental flaws in its design.
It would be pretty hard to fix them without breaking backward compatibility.
tl;dr: Obvious troll is obvious.
[1] http://www.gigamonkeys.com/book/lather-rinse-repeat-a-tour-o...
[2] http://en.wikipedia.org/wiki/Game_Oriented_Assembly_Lisp
tl;dr: lisp zealots are funny and arrogant
UPD: FYI, AutoCAD is NOT written in Lisp, it just supports extensions written in a dialect of Lisp.
With RTTI and Exceptions disabled you should be able to get almost identical performance with C and C++. In some cases C++ compiler has additional information that can allow it to produce faster code as well.
You're pretty much left with C with namespaces at that point.
If you use a custom quicksort implementation and put it into the same translation unit as the comparison function (or compile statically and use link-time optimizations with a sufficiently advanced compiler) you can get the same performance out of C.
Check out Stroustrup's keynote at Going Native 2012 for more details: http://channel9.msdn.com/Events/GoingNative/GoingNative-2012...
One thing I love about Torvalds and that makes him great is that he has zero respect for fads. CS is unfortunately very, very faddish. Good ideas like OOP and Agile become fads, and then become universal hammers with everything becoming a nail, destroying whatever virtues these ideas once had.
It makes some good points, despite the inflammatory technique of characterizing Linus' rant as being caused by a "C-hacker syndrome".
The fact that he leads with "language X sucks because it attracts type Y programmers" is quite possibly the worst, cheapest, and lowest attack I've ever seen in technology. It's sad that a technical hero like Linus would basically behave like such a tantrum-throwing child. It reflects poorly on the whole tech community.
Today isn't Thursday is it?
We see a similar point being made against Rubyists and Rails developers on HN quite often, alas. And, worse, in the "I'd learn Ruby but it seemed like there was too much drama" crowd.
I can't even count the number of times I've heard the "Perl sucks!" mantra (often from people who have little if any experience with the language).
That sort of attitude reminds me of this diagram:
http://img822.imageshack.us/img822/9872/programmerheirarachy...
C++ occupies an interesting point on the curve of fascination vs. utility, but to call it the most fascinating language (by your own definition especially) is just hyperbole.