In my opinion, video games are a great example of a place where you *should* use C++. Kernels and systems-level software are a great example of a place where you should *never* use C++.
Why do I say this? Well, C++ was designed to increase the speed of development and allow you to mix high-level and low-level code easily. It is very good at doing those things. At the same time, a clever programmer can get reasonable performance out of C++ by spending a little time optimizing.
When writing a video game, you don't care that much about long-term maintainability or safety. An exciting game that crashes a few times a month will sell many more copies than a boring game which is rock-solid. Stuff gets rewritten from scratch every few years to take advantage of the latest and greatest hardware. If things are not written in the absolute most efficient way, who cares? You just keep tweaking things until the game runs all right on the target hardware.
Kernels are the opposite. There are still pieces of code in the Linux kernel that go back to the early 1990s. Maintainability and stability are much more important than features or speed of development. It's important to use a simple style, in a simple programming language, that many different contributors can understand and use. Efficiency is key-- we don't have extra cycles to burn on things like std::string or std::map. In some structures, people are reluctant to enlarge the structure even by 4 bytes for performance reasons.
A lot of people claim that C++ is somehow safer than C. But this is ridiculous. C++ has all of the different flavors of undefined behavior that C does, plus many, many more. C++ has a lot of "generated code"-- default copy constructors, default destructors, and so on, that will burn you if you're not careful. Again, it's about speed of development, *not* safety.
Claiming that C++ is faster than C, or even as fast, is equally ridiculous. Even the most basic operations in C++, like iostreams, are much slower than the C equivalents like printf. Maybe some kind of theoretical perfect programmer could write equally fast, or even faster, code in C++ than C. But in the real world, programmers will take shortcuts if they exist. Let me draw an analogy-- if your wife bakes a cheesecake for you every night, you're going to get fat. Yes, in theory you could not eat the cheesecake, but it's right there.
So we're left with the real C++ advantage-- speed of development. I want to be fair here. C++ is good at doing what it does. But let's not get confused here-- it's not the right choice for a lot of projects. Use the right tool for the job.
Object-oriented design patterns in the kernel, part 1
Posted Jun 7, 2011 3:40 UTC (Tue) by elanthis (guest, #6227)
[Link]
You're making a few claims I have to disagree strongly with, but in few words as ive got to walk out the door in a few. First, I don't think you are quite in tune with game development, at least not professional game development. Stability and even security are quite important - nobody wants to be Fallout New Vegas. Second, game engines are not rewritten that often. All of the popular engines are well over a decade old, and the majority of the code has not changed in architecture at all. Most crashes you see in games are actually video driver crashes, save a few particularly poorly engineered titles.
C++ is very much a safer language. You bring up hidden code and such as if that makes it unsafe, which is silly. C++ doesnt just magically do things wrong behind your back anymore than C does. Yes, a destructor runs "automatically" but never ever unexpectedly. On the other hand, C requires programmers to cut-n-paste large swaths of boilerplate code, leading to a much higher bug count in general.
Simple fact is that there are kernels written in C++ which work very very well.
Object-oriented design patterns in the kernel, part 1
Posted Jun 7, 2011 6:13 UTC (Tue) by cmccabe (subscriber, #60281)
[Link]
> First, I don't think you are quite in tune with game development, at least
> not professional game development. Stability and even security are quite
> important - nobody wants to be Fallout New Vegas
Look, I'm not trying to trash game development or game developers. I know you guys have a difficult and challenging job.
But let's be realistic. If I'm the project manager and I have a choice of releasing with a crashing bug or two or releasing a game that is dull or outdated, I am going to release with the bugs. If I don't, I'm going to get fired. Nobody wants a game that looks like it should have come out last year.
On the other hand, the economics are different for some other kinds of software.
> C++ is very much a safer language. You bring up hidden code and
> such as if that makes it unsafe, which is silly
It's not silly at all. Every time I write class with any kind of non-trivial destructor, I have to remember to hide the copy constructor and assignment operator. If I fail to do this, a simple typo later in the program-- say typing use_foo(Foo f) instead of use_foo(Foo &f)-- could bring the program to its knees.
Or take conversion constructors or default parameters. Here's a true story of something that happened very recently. Someone on our project decided to change a function prototype from foo(int i) to foo(const MyObject &o). What he didn't realize was that there was a conversion constructor from an int to a MyObject. So when he overlooked this little gem:
> foo(0)
The compiler happily generated this:
> foo(MyObject(0))
Needless to say, the results were not what he intended at all.
Implicitly generated code hurts. Default constructors hurt. Default parameters hurt even more. You might disagree, but I've had a lot of time to come to this opinion.
> Simple fact is that there are kernels written in C++ which work very very
> well.
Well, as I already mentioned, there is XNU, which has no templates, no RTTI, and no exceptions, but is "technically C++". Apparently the Windows NT kernel also has some kind of C++ support-- again, I think exceptions are left out, as well as who knows what else.
I would say a bigger C++ success story is the success of the LLVM project. They managed to write a very capable compiler in C++, which has been gaining a lot of momentum. One of my friends who works on the project is also one of the few people who can stump me with a C++ question. I guess it's hard to out language-lawyer the language implementers!
But oh, they don't use exceptions :) And the LLVM library is 20MB when compiled, whereas /usr/bin/gcc is 262kb.
C++ has been the inspiration for a lot of other languages like Java and Golang, and I respect it for that. It got a lot of things right, and it's still the language that I know the best. But can't we have some new ideas after all these years?
Object-oriented design patterns in the kernel, part 1
Posted Jun 7, 2011 6:24 UTC (Tue) by elanthis (guest, #6227)
[Link]
Sure, there's cases where C++ bites you. There are cases where C does this, too, and there are many ways in which C++ helps you.
I doubt I'll convince you to change your opinion with anything short of a small novel, though. :)
Object-oriented design patterns in the kernel, part 1
Posted Jun 7, 2011 7:46 UTC (Tue) by jezuch (subscriber, #52988)
[Link]
> And the LLVM library is 20MB when compiled, whereas /usr/bin/gcc is 262kb
Are you sure you're not looking at just the GCC driver that invokes the actual compiler?
jezuch@zx-spectrum-1:~$ du -shc /usr/lib/gcc/x86_64-linux-gnu/4.6/{cc1,cc1plus,lto1}
11M /usr/lib/gcc/x86_64-linux-gnu/4.6/cc1
12M /usr/lib/gcc/x86_64-linux-gnu/4.6/cc1plus
11M /usr/lib/gcc/x86_64-linux-gnu/4.6/lto1
33M razem
Object-oriented design patterns in the kernel, part 1
Posted Jun 7, 2011 18:54 UTC (Tue) by cmccabe (subscriber, #60281)
[Link]
I stand corrected. I thought that binary was way too small... but ldd didn't tell me anything useful.
It's been a long time since I built gcc. Even back when I did embedded stuff, we always seemed to use prebuilt toolchains.
Object-oriented design patterns in the kernel, part 1
Posted Jun 9, 2011 14:21 UTC (Thu) by renox (subscriber, #23785)
[Link]
> Implicitly generated code hurts. Default constructors hurt. Default parameters hurt even more. You might disagree, but I've had a lot of time to come to this opinion.
Sorry but C++ poor mix of features doesn't mean that those features are always bad..
Plus C's lack of initialisation also hurt a lot, no?
Object-oriented design patterns in the kernel, part 1
Posted Jun 9, 2011 16:56 UTC (Thu) by jd (guest, #26381)
[Link]
Well, no. Implicit code is (IMHO) always a Bad Thing because when the specs or compiler change, the resultant binaries will change behaviour when given the same source.
The source is a specification document, to all practical intents and purposes, which the compiler uses to generate a program. If the program can change in nature for the same specification, the specification is incomplete and insufficient.
In other words, by depending on something external (in this case, the compiler) you cannot do reliable testing. There are too many external parameters that you can never reliably take account of. Good engineering practice is to always work to reduce or eliminate the unknowables. If the compiler is any good, it'll ignore initializing to the compiler's defaults since the instructions generated by the compiler's default will already be present. If the compiler isn't any good, you really shouldn't be trusting it to be doing the Right Thing anyway.
If you explicitly initialize, you always know the state of a variable, no matter what new C or C++ standard is produced. This is guaranteed safe.
Compiler-tolerant software is necessarily well-engineered software. Yes, it's more work, but if you wanted to avoid work, you'd not be using C or C++, you'd be using a fourth- or fifth-generation language instead. The only reason to use anything in the C family is to be able to balance development efficiency with code efficiency. Higher levels of language offer better development efficiency, lower levels (Fortran, assembly, etc) offer better code efficiency. Neither is useful on its own for something like an OS kernel, which is why nobody writes general-purpose kernels on the scale of Linux in either Erlang or IA64 assembly.
(Kernels do exist in both those, and indeed in Occam, but because of tradeoffs are almost always much more special-purpose.)
Object-oriented design patterns in the kernel, part 1
Posted Jun 13, 2011 0:20 UTC (Mon) by cmccabe (subscriber, #60281)
[Link]
> Plus C's lack of initialisation also hurt a lot, no?
I remember a thread here on LWN a while back where people were complaining about a performance regression in the kernel caused by zeroing struct page. So it seems that at least in some corner cases, not initializing memory is a feature. In a perfect world, non-initialization probably should be something that the programmer has to ask for specifically, rather than the default. But C was designed in the 1970s-- give it a break already.
When C++ was designed, in the mid-1980s, the decision was made to keep all the old uninitialized variable behavior and add some more. So if you create a C++ class with some primitives, and forget to initialize them in one of the constructors, they'll be uninitialized. This also applies to copy constructors. The rationale was that programmers shouldn't have to pay for what they didn't use.
Luckily there is some relief in sight, in the shape of Coverity and similar static analysis tools. These can catch most uninitialized variables.