http://www.flickr.com/photos/dnnya/3913422184/

Why C++11 feels like a new Language

Martin
3 min readJun 25, 2013

For many of my colleagues and friends C++ is still a language of many mysteries, complexities and not agile enough. Often, the Ruby collection API is referenced with it’s more functional approach compared to C++ standard containers. And when switching forth and back between Ruby, Python, Scala and C++, yes C++ may sometimes feel a little bit dusty.

But not anymore, C++11 is here and brings a tons of new features that help to develop the language in a better way and make it more modern. Well, yes, the process of incrementally improving C++ is long and complex and takes exponentially more time compared to smaller languages like Ruby, but there is progress.

But let’s come back to the title: Why does C++11 feels like a new language? Because you can! Not voting for a new president, but rather use lambdas everywhere giving you the necessary freedom.

Let’s consider the simple example of selecting items from a list of object that match a certain criterion and then transform this list into a another list. Basically, all we want to do is to use to functional programming paradigms fold and map. The corresponding Ruby would look like this:

data.select {|user| user.level > 10}.collect {|user| user.name }

That looks nice and easy. Now what would the old C++ version probably look like:

std::vector<std::string> result;for(std::vector<User>::const_iterator begin = data.begin(), end=data.end(); begin != end; ++begin) {
if (*begin.level > 10)
result.push_back(*begin.name);
}

It doesn’t look that bad, but from a conceptual level it combines these two functions into one. In addition, reusing this code block is almost impossible. But, can we write this in a more idiomatic way for C++11?

auto fold = select(data, [](const User& u){ return u.level > 10; });
auto result = collect(fold, [](const User& u){ return u.name;});

That looks so much better and the best thing is that it’s not limited to vectors of Users, but basically anything that accepts begin/end and provides an iterator interface. There are two major components that we use from the standard library to implement the select and collect functions: First of all lambdas. Omni-present in languages like Scala and Ruby, under-valued in Python and anonymous classes in Java. Finally the brave new world (wait is Lisp new?) arrived to C++ and lambdas are nothing more than syntactic sugar around function objects —why couldn’t we have this earlier?

Now, that we have lambdas we basically use two functions from the standard library copy_if and transform.To explain this, let’s look at the implementation of select:

template<typename T, typename F>
auto select(const T& values, F func) -> T {
T result;
std::copy_if(std::begin(values), std::end(values),
std::back_inserter(result), func);
return result;
}

From the documentation, copy_if applies a function to a range and copies the current value from source to destination if the function returns true. std::back_inserter is a nice helper function that allows us to directly append a new values to a container without having to manually code the push_back for the vector and is more agnostic to the underlaying container.

Now, let’s look at the collect implementation: This one would almost work exactly like this in C++03 without the lambdas.

template <typename T, typename F>
auto collect(const T& values, F func) -> std::vector<decltype(func(*std::begin(values)))> {

typedef std::vector<decltype(func(*std::begin(values)))> result_type;
result_type result(values.size());
std::transform(std::begin(values), std::end(values), std::begin(result), func);return result;
}

While this looks weird in the beginning the definition of the return values for this function is basically genius. decltype is a new operator in C++11 that evaluates an expression at compile time to detect it’s type definition. In the above example, it will evaluate to the return value of the function object that we supply. This means we can write the complete definition of this function without ever knowing the return values in advance but rather rely on lazy compile time evaluation. Awesome isn’t it?

To summarize, the availability of operators like decltype and lambda expressions allow writing much more concise code that better reflects the programmers intentions. Never again must C++ coders hide when it comes to functional programming paradigms.

--

--

Martin

Systems dude, currently pushing the boundaries of what can be done with Spark. Opinions are my own.