Heise Developer: Gelernt aus Fehlern

For you German speakers out there, Heise Developer just published a re-issue of my C++0x overview article from the 2009 Programmieren Heute, called “Gelernt aus Fehlern“.

Compared to the print version, we’ve updated the content in some places, such as spending less time on the removal of concepts and more about the adoption of the new standard, as well as turning the Top 10 into a Top 11 to celebrate the new standard 🙂

From the article:

Die spannendste Frage wird sein, wie schnell sich C++11 gegen seinen Vorgänger C++98 wird durchsetzen können. Es war in den vergangenen zwei Dekaden regelmäßig notwendig, C++-Neuerungen konservativ einzusetzen, da Compiler den Standard nur zögerlich umgesetzt haben. […] Hier muss sich die C++-Gemeinde umgewöhnen. Neuerungen wie Lambdas und auto machen C++11 zu einer deutlich produktiveren Sprache, als C++98 es war. Es gilt nun, diese Produktivitätssteigerung im Alltag auch zu nutzen, um gegen Java und .NET zu bestehen. Ein weiteres Jahrzehnt der Zersplitterung und Inkompatibilität könnte die momentan exzellente Ausgangsposition von C++ schnell wieder zunichte machen.

Hope you like it.

Advertisement

C++98 Support Costs Extra!

I should note, right up front, that this post reflects my personal opinion and not that of my employer. In particular, KDAB currently does not require extra payment for C++98 support, even though, as this post will make abundantly clear, I personally wouldn’t mind if it did :).

So, the new C++ standard is finalised and voted on unanimously. Does that mean that we’ll have another decade of C++ incompatibilities ahead of us?

My answer to that is: That depends on us.

Will we adopt C++11 faster than C++98? Our compilers do. Will we make use of the new productivity gains (auto, range-for, lambdas, …) or will we continue to castrate our code to work with 15-year-old compilers? The answers of the majority of C++ programmers will determine how the next decade goes for all of us.

In this post, I’ll argue (strongly) for dropping C++98 support asap, and using C++11 to the fullest possible extent in all our projects. This includes dropping support for compilers and platforms that don’t (yet) support C++11 to the extent required by a particular project instead of #ifdefing our way around it, as we (as an industry) have done for the past 30 years. Will these compilers and platforms be left out in the cold? Not really: they will have older versions of libraries and programs to support them. But yes, newer versions will require an up-to-date C++ compiler.

Is this realistic? I think it is.

Essentially, we have this situation already now. Many projects require fairly recent versions of libraries, precisely because 1) there’s not much point in supporting older versions, and 2) supporting many versions of one library with the same code-base is fairly expensive. I’ve tried. Gpgme++ theoretically supports gpgme’s that can be considered stone-aged. Has anyone ever tested this? Hmmm… How many Mac applications still support OS X 10.2? 10.3? 10.4? Half of the web doesn’t work anymore on KDE 3.5’s Konqueror.

Then why should we be so conservative when it comes to C++, the very core of what we work with? It’s not even customer-visible. Why do we accept an STL shipping in 2011 that is basically unchanged from the mid-1990s? Why do we #ifdef our way around MSVC6 problems in 2011? Why do we care about the quirks of GCC 3.3, or heaven forbid, 2.95?

My new-year’s resolution (ok, it’s a bit early, but hey): stop it!

C++11 support in C++ compilers now is much stronger than C++98 support was in 1998 in the then-C++-compilers. I fully expect every C++ compiler to have caught up on final C++11 with its next major release, except for source-code invisible changes like the new memory model. I want Qt 5 to require a C++11 compiler. I want KDE 5 to require a C++11 compiler. I will lobby inside KDAB to do the same.

Why? Because I’m a programmer, and we’re lazy.

I want to use auto. If you make me type std::map<std::string,std::string>::const_iterator instead of auto, it’s more work, less fun, so you should need to pay extra.

I want to use lambdas. If you make me write

struct ByName : std::binary_function<Foo,Foo,bool> {
    result_type operator()( const Foo & lhs, const Foo & rhs ) const {
        return lhs.name() < rhs.name() ;
    }
};

instead of [](const Foo &lhs, const Foo &rhs) { return lhs.name() < rhs.name() ; }, it’s more work, less fun, so you should need to pay extra.

C++11 is a much more productive language than C++98. We as an industry can, however, only reap that productivity gain if we stop throwing C++ productivity out of the window by the bucket-load in the hopeless pursuit of compatibility with non-standard implementations. The worst offender, Microsoft, has seen the light. Their current compilers are very standards-compliant, and actively maintained. I hope that Apple won’t be the next blocker: By choosing Clang over GCC for—apparently—political reasons (GCC 4.2 was the last GCC with GPLv2), they have lost at least one year of C++11 support that GCC and VC are ahead of Clang. Let’s hope Clang catches up soon.

[[EDIT 2011-09-21: If you think that VC isn’t implementing C++11 fast enough, you can make yourselves heard here: http://visualstudio.uservoice.com, in particular here and here.]]

[[EDIT 2012-03-30: Microsoft has announced that the VC++ compiler will have a faster release cycle than Visual Studio. That makes me hope that we’ll see a “reasonably conforming” (Sutter) VC++ a long time before 2014. Also, Clang++ 3.1 has caught up a lot with GCC (http://clang.llvm.org/cxx_status.html#cxx11, 3.1 currently shows up as “SVN”); it seems tooling will indeed not be the problem, after all.]]

Early-Bird Registration open for “In-depth Multi-Threading with Qt” @ DevDays

I’ll be giving a two-day “In-depth multi-threading with Qt” training just after the DevDays in Munich, ie. Oct 27th-28th. The training language will be English. The training material is the one from the usual Qt training, but “seriously expanded” to fill the two-day schedule.

From the announcement:

This two-day training teaches how to use multithreading with the primitives provided by Qt. Participants will gain insight into multithreading problems in general, and how they pertain to Qt programs in particular.

Examples include how to offload work from the GUI thread, how to increase throughput to the maximum in your application, and optimal strategies for communication between threads.

The training covers topics such as cross-thread signal/slot connections, QThreadPool, QObjects and multithreading, QtConcurrent, QFuture, and Qt atomic operations.

Participants are expected to have a working knowledge of C++ and Qt. Prior experience with multithreaded programming is recommended, but not necessary. The course will start with a one hour multithreading refresher.

To book, visit http://www.kdab.com/schedule.

Until October 1st, you’ll save 200€ on the early-bird offer. Just use d94ec6fd in the Voucher(s) field.

Hope to see you there!

Understand the Qt Containers: The Data

This is just a short heads-up to those that have asked for quantitative measurements. I’ve begun updating “Understand the Qt Containers” with a section on data.

As of now, the memory and append performance is in. I’ll re-run the iteration test over the night once more (I’ve detected an anomaly that I’d like the verify first), and re-add them again, when done.

Effective Qt: Understand the Qt Containers


The third of my Effective Qt columns, “Understand the Qt Containers“, just went live on my site.

If you know me, you will know what awaits you there 🙂 I hope I have not disappointed you. That said, this is just a first part. I plan to eventually extend it to cover more containers (currently, just QVector and QList), and give more data and assembler code for the containers I’ve already described.

These are the guidelines this item covers:

  • Remember that QList has nothing to do with std::list, and QSet has nothing to do with std::set.
  • Be aware of the two Qt container APIs, Qt-ish and STL-compatible, and avoid mixing their use in the same project.
  • Familiarise yourself with the STL containers and the additional features they offer.
  • Prefer member-swap over assignment wherever possible to express move semantics. Use C++11 rvalue move semantics if the class and the compiler support them.
  • [[EDIT 2011-08-25: new]] Always use constBegin()/constEnd() (cbegin()/cend()) when assigning the result to a const_iterator.
  • Avoid modifying a container (remove/insert elements) while iterating. If you have to, use an STL algorithm, such as one of the std::remove() family.
  • Prefer the STL-compatible iterators over the Java-style ones.
  • If you do use the Java-style iterators, avoid using the mutating ones.
  • Prefer to use const references as the first argument of Q_FOREACH, unless the element type is customarily passed by value.
  • Familiarise yourself with BOOST_FOREACH, and the additional features it offers.
  • Declare your enums and QFlags as Q_PRIMITIVE_TYPE if there’s a chance they will be held in Qt containers.
  • Declare your value-types Q_MOVABLE_TYPE if there’s a chance they will be held in Qt containers.
  • Don’t change the classification of a type if you need to maintain binary compatibility.
  • Prefer vector (std or Q) over QList.
  • Avoid QList<T> where T is not declared as either Q_MOVABLE_TYPE or Q_PRIMITIVE_TYPE or where sizeof(T) != sizeof(void*) (remember to check both 32 and 64-bit platforms).
  • [[EDIT 2011-08-16: new]] Avoid using vectors of types for which Qt APIs customarily use QList, and for which QList is not inefficient.

Hope you enjoy!

Translated: Pimp My Pimpl (part 2)

I’m happy to report that I finally sat down to translate the second part of my Heise Developer article on the Pimpl Idiom to English. Please find it here.

Effective Qt: Prefer to use normalised signal/slot signatures

The second of my Effective Qt columns, “Prefer to use normalised signal/slot signatures“, just went live on my site.

There is only one guideline this item covers:

  • Prefer normalised signal/slot signatures in connect statements.

Hope you enjoy!

On a Friday in July…


I usually don’t write or comment upon politics or news, but Friday’s attacks strike too close to heart to be left uncommented.

Having lived in Oslo for two years or so a few years back, I was shocked when my mom called me on Friday and said “did you hear about the Oslo bombing”? No, I hadn’t. I switched on the TV, and went to www.nrk.no to find out what had happened.

At first glance, it seemed that Norway had gotten away lucky: An apparently huge blast, in the capital’s centre, almost at rush hour, yet only seven dead. I texted my friends in Oslo and even though they are living or working near the blast site, they and theirs were unharmed.

That was then.

As I write this, we’re up to almost a hundred dead, with quite a few persons still unaccounted for. We know that the bombing in Oslo was just the prelude for a killing spree on Utøya, where a peaceful youth-get-together was underway. We know that the — predictable — initial commentators blaming Islamic terror were, for once, wrong, and we have to deal with the fact that this was an act by a Norwegian (dare I say Arian?) who cut’n’pasted together a 1500-page manifest while planning the killing for nine years.

But I don’t want to speculate on politics and police tactics.

My thoughts go out, instead, to the Norwegian people. Many will find that they have lost someone they knew, or know someone who lost someone, when the names of the victims will be published after their next-of-kins have been informed.

I’m desperately hoping that none of my friends and none of the Trolls will be among those. That’s selfish, in a way, but it’s all I’m currently capable of. The rest is deep sadness, and the hope that Norway doesn’t come out of this changed to the worse, and instead will continue to be the best country in the world to live in.

Translated: Pimp My Pimpl (part 1)

I’m happy to report that I finally sat down to translate the first part of my Heise Developer article on the Pimpl Idiom to English. Please find it here.

Refactoring in a GIT world


Mike McQuaid recently said in a mail regarding good style in GIT

Treat committing as being slightly more granular than saving a file. Do it very, very often.

This is a very succinct way of expressing something that you feel happening to yourself when you migrate from a CVCS to a DVCS: Commits become smaller. And so they should!

Take Refactoring as a specific case-in-point. We all say we’re refactoring all the time, but if we’re honest, we’re not really doing all the compile-and-test cycles that the book mandates after every minor step. Nor should we: they’re a waste of time, and a band-aid for the lack of proper tool support.

Automated tests, where available, are not usually designed for speed of execution. So it’s not uncommon for tests to run an unacceptably long time. And for a unit test, everything that exceeds one second is something that I consider too slow. Too long, to run each time you move a single line of code around.

Many will argue for a refactoring browser as a proper tool for the job. It can certainly help avoiding dropping-the-brick mistakes. But a refactoring browser cannot deal with more complicated refactorings, or semantic failures that a refactoring introduces. We still need the tests. We still need to limit the amount of changes in between tests lest we waste even more time searching for the specific change that broke a test (assuming we have it).

In fact, since a refactoring browser does the whole multi-step process in one big stride, it’s actually harder to find where it introduces a regression. There are probably refactoring browsers that optionally record each step of a refactoring in order to catch regressions; use them.

The problem also extends to the time after publishing the refactoring. In real-world projects, well-meaning refactorings still introduce regressions because there’s no 100% test coverage in that area of the code, or some users of the code use it outside of its design parameters. So, regressions will often show up further down the line.

Now, git-bisect is a very good tool for finding the commit that introduced a regression, but it doesn’t help much if the commits are too large. But what is a good commit size?

The Refactoring book gives a very clear answer to that: just replace compile-and-test by compile-and-commit, or just ‘commit’. Once the whole refactoring is done, you let your extensive test suite run on the result. If you broke something, you use git-bisect to find the commit that broke it. Since each commit is a trivial change, you’ll never search for the bugger, git-bisect will find it for you.

Even better: when you don’t squash the series of commits that make up your refactoring when pushing upstream, any regressions that you may have introduced and that were not caught by your test suite will still be pinpointed by git-bisect, in a trivial manner.

Here is a summary for doing a refactoring in GIT:

  1. Indicate that you’re doing a refactoring, and which one, by using a common prefix for all summary lines of the commits involved. Example: “FooBar: Extract Method doCalculate(), pt.N: use new doCalulate() in doStuff()”
  2. Commit at least as often as the book says you should compile-and-test.
  3. Run the tests only once, at the end
  4. If something breaks, use git-bisect to find the bad commit, and rewrite history.
  5. Don’t squash the commits when pushing. If colleagues complain about your tiny commits, complain about their large commits, and point them to this post 🙂

Is it worth it? Is the extra time you spend writing commit messages offset by the time you save when something goes wrong? Immediately, or later on? I don’t know yet. But if the experience written down in Fowler’s book is to be trusted, there’s a high probability it should.