But Linus said...
But Linus said...
That said, this absolutely doesn't mean that you CAN'T do systems level programming in C++. I've actually done real RTOS and motor control work on a small embedded platform that went in a robot using C++! This is in an actual shipping product too, not just a hobby project...
As Linus said, it's definitely easier to come up with something inefficient in C++, and you do have to limit yourself to a sane set of features. That said, I think some of the things C++ brings to the table can make development a lot easier without sacrificing performance as long as you have a disciplined team and sane coding guidelines. But what makes sense for a personal project or a small team may not make sense for a larger project, and while I think Linus is justified in his opinion, you definitely shouldn't take it to mean that you CAN'T do systems programming in C++.
> as long as you have a disciplined team and sane coding guidelines
Is it not possible at all anymore to just hire people actually understanding what they are doing? Or cargo cult is here to stay?
I am sorry - please don't take that as a personal attack, but explaining people that C++ can actually be used in OS development by mindlessly sticking to some rules doesn't seem a way to me... but rather a counter-argument to what you said yourself.
As an example: When I was working on a project for a very constrained embedded device, we needed to get some extra man-power on our team for a few sprints to help out with some functionality. One of the pieces of our system was a "debug console" I had written that allowed some interactivity with the system over a serial port. The new guy was a very sharp engineer, but he typically worked on higher level stuff than we were doing. He wanted to add some functionality to the debug console, and dutifully started writing stuff in using the C++ string handling libraries. And consequently he blew our stack budget, and we ended up very quickly rewriting part of it together.
Now, the point is he wasn't doing anything using some crazy STL functionality or Boost, and he was doing the "right" thing by handling strings using the Standard Library functionality. What we had to do for our system was actually bend the conventional knowledge ("Don't write a string handling library yourself"), because we knew exactly what we needed, and exactly what resources we had.
So perhaps I could have phrased my point better. When I say "have a disciplined team and sane coding guidelines", I don't mean a team that codes by the book, I mean a team that knows what it is doing, and knows when the rules are meant to be bent. In our case sane coding guidelines meant we did things that were against the conventional wisdom, but they were sane, because they were justified in our case based on our engineering analysis. We were certainly open to breaking / changing these guidelines but it had to be justified. (And in fact our 'guidelines' were less a set of rules about how you needed to do every last detail, and more of a set of project specific "design patterns" and a large set of lessons learned in a shared wiki page which described issues we had run in to, and justified certain design decisions that were made)
(Edit: Other examples included disabling RTTI, and completely disabling and disallowing the usage of C++ exceptions to write our own error handling. Against the common advice to use what the language gives you, but made sense for our application)
Again, no need to apologize! I could have made my point clearer, and I hope I did, but please feel free to follow up with me! I'm always looking for ways to improve :-)
(Your post is better than mine, though.)
Easy to do. Tough to always remember the impact of what's going on under the hood.
At least, that's what I hazily recall from the long, jumbled Perl 6 history, but that includes a few changes to the language and multiple VM's and multiple string handling regimes per VM, sometimes.
e.g. say you're working on an embedded system, and you want a string, so you do:
std::string s = "fnord";
At first it seems to work fine --- but you firmware image's RAM requirements have just gone up by 32kB, and a week later there's a crisis when adding another feature causes the system to stop linking because the RAM address space is full.What happened is that std::string uses the heap to store the string data, so adding the line above caused the linker to pull in all the heap code and allocate a 32kB block of RAM to put the heap in. Because previously, the product wasn't using a heap: it was using static memory allocation throughout.
That example's contrived, but only a little. I've done the must-avoid-dynamic-memory-allocation dance many times in real life. (I've also discovered that printf() requires a raise() implementation on some platforms.)
A more realistic one is that embedded platforms typically have RTTI turned off, which means no exceptions, which means no throwing exceptions from constructors, which means two-phase construction throughout your program and you have to be really careful about which bits of the STL you use...
> At first it seems to work fine
It so happens that I have been working in OS- and low level areas for many years, and independently am also a pretty early adopter of C++. I have a reflex of routinely giving a quick glance to the link map, and am frequently dumping assembly for areas of code I have doubts in.
All this to say that reading 'it seems to work fine' in the context of OS development kind of provokes a skin reaction in me.
C++ has it's place in OS development, but you need to know exactly what code is being generated, and you need to understand with excruciating precision how memory is being allocated.
I'm the author of the mentioned project. It's indeed a very annoying opinion. Although there are indeed some difficulties in writing an operating system and quite some runtime support to implement, I would say that it's worth it only to have a more powerful language. I'd rather use a language that I really like rather than be forced to use one I don't really care about.
I cannot say that C++ is the best language to develop an operating system, but I would definitely say that it's possible if you really know the language. And you don't have to use the complete language (I didn't enable exceptions nor RTTI in my OS).
From the CppCon 2016 presentation description:
"Early in the design process we made a hard choice; no C interfaces and no blocking POSIX calls. We’ve done everything from scratch with modern C++ 11/14 - Including device drivers and the complete network stack all the way through ethernet, IP and ARP, up to and including UDP, TCP and recently also an http / REST API framework. To achieve maximum efficiency we decided to do everything event based and async, so there's plenty of opportunities to use lambdas and delegates." [1]
[1] https://cppcon2016.sched.org/event/d30a43dae4a490dce81a3dfc6...
We also have a chat if you have any questions: https://gitter.im/hioa-cs/IncludeOS
Maybe it's meant to be hard in the "we decided we weren't going to be POSIX compliant which has implications" send and not the hard to implement sense?
They had zero vendors willing to put their OS on a box and resell it because MS threatened the vendors with pulling their right to sell Windows if they did. This wasn't particular to Be, but to any other OS.
However regarding Microsoft, I actually think that vendors were as guilty as Microsoft.
They could have chosen not to take Microsoft's discount and try to sell alternative OSes, even if it meant having to face a few challenges.
The one that takes is as guilty as the one that gives.
I did a quick search and came up with Quora answer given here: https://www.quora.com/Why-was-the-BeOS-dropped
but this doesn't jive with my memory. I will have to see if I can find an old email or maybe dig further on the net. I certainly don’t want to be rewriting history.
I remember quite a few small shops trying to put a fight selling other kinds of computers, they might have lost in the end, but they tried to walk a different path.
The only real beef I have with C++ is its complexity. As I did less and less high-level programming, I forgot about many of C++'s pitfalls and nowadays I'm always tiptoeing when I have to write C++ code. I think a lot of it is unwarranted, or at least not needed when you're writing system-level code (but my impression may be distorted by the fact that I'm used to embedded systems and high-reliability applications; my sight may be narrow here).
Edit -- oh, by the way: it's worth pointing out, in the context of a thread that mentions Torvalds' opinion on the matter, that the whole thing was written a while ago.
The Internet endlessly recycles some of these arguments, e.g. STL still gets a lot of criticism that hasn't been true in a while. Yes, STL was terrible, terrible fifteen years ago, but that's, like, 50 years in computer years.
The advanced template techniques (and to a degree, I'm throwing type deduction in there too), when treated skeptically do lead to more efficient code. It's easy to go off the deep end though, which is why I said "when treated skeptically". As for lambdas, we have an entirely asynchronous OS, so they're really nice for callback glue.
EDIT: Binary literals actually come up way less than you'd think, even for deeply embedded (I think the smallest thing we ship on currently is 16KB of RAM). Everyone here knows hex like the back of their hand.
Solid argument that.
His two other arguments:
- infinite amounts of pain when they don't work (and anybody who tells me that STL and especially Boost are stable and portable is just so full of BS that it's not even funny)
Considering that the linux kernel is strongly tied to the specific C dialect supported by GCC and is not portable at all, this argument is bullshit.
- inefficient abstracted programming models where two years down the road you notice that some abstraction wasn't very efficient, but now all your code depends on all the nice object models around it, and you cannot fix it without rewriting your app.
You can abstract yourself in a corner in C as well. In C++ you are more likely to pay less for abstractions.
Sorry, but I take it personally when me and my colleagues are called substandard programmers.
It's much, much harder to do than in C++. It's also much more obvious when it happens, and in collaboration others will spot it quickly.
His tone is harsh but I find it completely right. I prefer to use C at work exactly because the same kind of software would be an absolute nightmare to write in C++ (it is very low-level soft, extremely similar to kernel code).
C++ is good if you can enforce very strict guidelines and if every single programmer that contributes to the code is very good at C++. Those are pretty big if, especially if you work with a partially open source codebase.
Templates may bloat your binary size and increase compile times, but they're plenty fast.
Linux has been ported to over two dozen architectures so it is extremely portable. Yes, it is tied to some GCC behaviors, but many operating systems are tied to compilers. Some extensions make the code identical across different archs, like __builtin_return_address.
Windows is tied to particular C features, which is why MSVC is resistant to C99. Plan9 was a special dialect and compiler of C.
http://www.boost.org/doc/libs/master/libs/context/doc/html/c...
I don't know what kind of programming you do, but he is talking mainly about kernel programming. He is mainly criticizing the people who want to bring C++ in the kernel world. Anyone is welcome to prove him wrong.
But I think, C++ is more suited for applications programming, where efficiency is not a prime concern and abstraction-costs are justified.
Even in such cases, (e.g. git, which is an application program) an excellent programmer like Linus can be very well productive with C and does not need the (sloppy/non-sloppy) abstractions provided by C++.
>>You can abstract yourself in a corner in C as well. In C++ you are more likely to pay less for abstractions.
Agreed. But the point you seem to be missing is that C doesn't force any abstractions on you. The STL/Boost abstractions are much more inefficient.
Linus talks about these inefficient abstractions and that's a solid argument because C++ abstractions come with various sorts of hidden costs. (e.g. even name mangling can be a significant cost factor in Kernel.)
>>Considering that the linux kernel is strongly tied to the specific C dialect supported by GCC and is not portable at all, this argument is bullshit.
The issue of portability to different compilers is not an important concern for kernel programmers. If they find a particular tool (e.g. gcc with some C dialect) perfect for their purpose, why should they bother with other tools?
Remember, for Linux kernel programmers gcc is just a tool to produce their product, the kernel.
edit: added point about portability
This specific rant was about using C++ in git. BTW I work in what could be called soft realtime systems.
> But I think, C++ is more suited for applications programming, where efficiency is not a prime concern and abstraction-costs are justified.
If efficiency is not a prime concern, using C++ is hardly justified.
> [...] the point you seem to be missing is that C doesn't force any abstractions on you.
Nor does C++.
edit:
> Even in such cases, (e.g. git, which is an application program) an excellent programmer like Linus can be very well productive with C and does not need the (sloppy/non-sloppy) abstractions provided by C++.
and that's perfectly fine, if one feels more productive in a certain language, more power to him, but please let's not spread FUD.
Well, yes and no. Yes, I agree with you as C++ gives you more control than most other high level languages out there, e.g. more control over how you manage your memory. I can hardly imagine someone writing kernel in managed languages, like, Java.
No, I don't agree with you because sometimes, when very low-level aspects of machine also become prime efficiency concern, using C++ is hardly justified. See my point about C++ not forcing any abstractions on you, given at the end.
It reminds me what someone once half-jokingly said about C and assembly: "C gives you all the power of assembly language with the same ease of use".
In the kernel world, it becomes a joke, as the level of abstraction provided by C is very high as compared to the one provided by assembly language (e.g. mainly due to struct, union and cleaner subroutine syntax) and the cost of this abstraction is extremely low.
The benefits of using C are tremendous: e.g. code portability and readability.
>>Nor does C++.
Yes, but when you don't use any non-c abstraction provided by C then it reduces, almost entirely, to C (barring templates).
Templates are extremely good mechanism to provide abstraction (especially as compared to inheritance) but their cost (e.g. cost in terms of code bloat and in terms of the cognitive load if one actually wants to dig deeper and see/tweak the generated code to investigate/address some performance issues) seems prohibitive at least in the performance sensitive kernel programming.
The kernel hackers have found a neat-but-not-so-neat way around it: by using C macros. Macros are in fact C's templates. I am not saying macros lead to cleaner code and so on but when you compare them to C++ templates, their cost-benefit equation in the kernel programming world seems justifiable.
>>and that's perfectly fine, if one feels more productive in a certain language, more power to him, but please let's not spread FUD.
I agree with you whole heartedly about one's choice of language. I personally would have chosen C++ and even Python over C to implement an application like git or its parts.
Not to play advocate for Linus here (he doesn't need a half-witted advocate like me), but he seemed to be spreading FUD about C++ because, supposing C++ were allowed, he seems to feel that many people will start using its abstractions without being aware of their costs. It's very easy to get tempted to use available abstractions and if the abstractions start leaking (as he pointed out) then fixing the code that relied on those abstractions becomes a difficult issue.
Apple and Microsoft already did.
https://developer.apple.com/library/mac/documentation/Device...
NeXT Driver Kit:
http://www.nextop.de/NeXTstep_3.3_Developer_Documentation/Op...
Windows 10 Windows Driver Frameworks:
Well, the STL/Boost libraries are designed for certain goals. If you have different goals, you should use something different. But in any case, which specific abstractions are you talking? Which scenario are you optimizing for and what common case, worst case perf numbers are you looking to hit?
>. (e.g. even name mangling can be a significant cost factor in Kernel.)
What in the world are you talking about?
I find that every abstraction level makes me more unhappy and somehow lost..
So yes, I do believe Linus knows something and for sure he's not trying to fool himself. When you really try to build something to actually be used, all those abstractions will bite you..
But yeah, smart pointers alone help a lot with writing tidy c++...
Many languages, including "simple" Java, are about as large as C++ right now ( https://channel9.msdn.com/Events/GoingNative/GoingNative-201... , around the one-hour and fifteen minute mark). To be honest, one thing that makes working in C++ relatively hard is the fact that C++'s standard library is significantly smaller than the competition. You have to do more yourself.
C++ the language is extremely complex and riddled with pitfalls and minefields. Just try to pin down the formal definition of such a widely-used term as "rvalue". OTOH I find the C++ standard library to be reasonably straightforward and well-designed. The STL in particular is brilliant.
So I would say it is mostly gaming. There are not many games on Linux (again, getting better, but it takes time), so gfx vendors do not allocate big resources to support it, so the developer-experience is suboptimal, the classic chicken-egg problem.
Yes, the latest VC++ do support C99 library, because it is required by the C++ standard and the new MSVCRT.dll is actually written in C++ with extern "C" entry points.
Very impressive either way - I was just curious how C++ was leveraged.
On the other hand, a lot of code is clearly very close to C. When you're doing some low-level things, parsing memory structures, paging, ... there are not a lot of features from C++ than can help. Moreover, there is a lot of code that could profit from some refactorings:P
Other parts of Boost have been considerably less impressive, and virtually nobody uses them. I struggled at length trying to get Boost::Parameter to work, with zero success. Boost::Format at least works, but ends up cumbersome, and does not approach the usability of {} formatting in Python.