Notes on "C++ and Beyond"

Posted on January 22, 2015

Last year I was lucky enough to attend to a set of talks by Scott Meyers, Herb Sutter, and Andrei Alexandrescu titled “C++ and beyond”. It was a true pleasure to listen, all three are very good talkers. I would like to summarize my personal opinions and thoughts on what I have heard. There were a few things mentioned that are seen as strong points in C++ (actually, C++14). Those included

While anonymous functions are available in C++, it doesn’t change the fact that the syntax is ugly and comparably unreadable. Look at this code:

std::vector<int> a = {1,2,3,4,5};
auto pr = [](auto a) {
for_each(a.begin(), a.end(),
     [](auto a) { std::cout << a << " "; }); };
for_each(a.begin(), a.end(), [](auto& a) { a = a * 2; });
pr(a);

which does more or less the same as this

let a = map (*2) [1,2,3,4,5] in print a

Now, I am not completely sure whether there is a shorter or more readable way to write the above C++ code, but I have a feeling that there is not.

Another thing I remember from the talks is the syntax of the so-called lambda init capture. Use your favourite search engine to find out about it, I personally think it hurts my brain.

Concerning type deduction using, for example, the /auto/ keyword, Meyers stated that there are at least *five different ways in which the compiler determines a type*, depending on where in the code the type is occurring. That does not sound like something I want to use a lot, even though I am a big fan of automatic type inference in general. Also, the error messages from the current compilers in cases where a type mismatch happens can be very unhelpful (lots of template error messages).

I wanted to know just how smart /auto/ is, so I tried it out while listening. What would you think happens here:

auto a = 42;
auto b = 1 << 36;
long long int c = (long long int)1 << 36;
auto d = (long long int)1 << 36;
long long int e = 1 << 36;

Go ahead and try. I used g++ 4.9.2 and together with a few lines for printing, it gave me:

Length of a: 4
Length of b: 4
Length of c: 8
Length of d: 8
a: 42
b: 0
c: 68719476736
d: 68719476736
e: 0

It works for /d/, but there you *told* the compiler what the type needs to be. So you don’t need auto, really. And even for /e/ it does not work, because the compiler assumes the /1/ on the right hand side to be an *int*.

Check out Haskell:

let a = 42
-- GHCi says: a :: Num a => a
let b = 1 ‘shiftL‘ 36
-- GHCi says: b :: (Bits a, Num a) => a
print b
-- results in 68719476736.

Seems smarter, really.

Concerning the *batteries included* concept, I like that very much. It’s just that it kind of doesn’t really work with C++ up until now, and other languages have been doing just that for a long time, such as Python, Haskell, and Java.

C++’s Concepts are still not there, while Haskell has it’s nice typeclasses.

Parallelism, on the other hand, seems to be a big issue also in the future development of C++. This is good, but still, there is no way for the compiler to assure that functions that may be running in parallel are not affecting each other. A pure language can do that, and Alexandrescu said something along the lines of “add purity to the language before trying to add STM”, with which I can only agree. Again, Haskell has purity and also Control.Concurrent.STM.

Another interesting remark that Meyers made was “It’s ok to learn new syntax if the code gets more readable”. I completely agree with that, and that is also an argument for *learning a different language*.

Please don’t get this wrong, I liked to be there and I enjoyed the talks. There was a lot of very interesting information about optimizing code and some stories from the field, which I enjoyed hearing.

Nevertheless, I am much less a fan of C++ than I used to be years ago, and I am promoting the use of more modern languages in practice wherever that is possible.