C++ Has Become More Pythonic
C++ has changed a lot in recent years. The last two revisions, C++11 and C++14, introduce so many new features that, in the words of Bjarne Stroustrup, “It feels like a new language.”
It’s true. Modern C++ lends itself to a whole new style of programming – and I couldn’t help noticing it has more of a Python flavor. Ranged-based for loops, type deduction, vector and map initializers, lambda expressions. The more you explore modern C++, the more you find Python’s fingerprints all over it.
Was Python a direct influence on modern C++? Or did Python simply adopt a few useful constructs before C++ got around to it? You be the judge.
Python introduced binary literals in 2008. Now C++14 has them. [Update: Thiago Macieira points out in the comments that GCC actually supported them back in 2007.]
static const int primes = 0b10100000100010100010100010101100;
Python also introduced raw string literals back in 1998. They’re convenient when hardcoding a regular expression or a Windows path. C++11 added the same idea with a slightly different syntax:
const char* path = R”(c:thisstringhasbackslashes)”;
Range-Based For Loops
In Python, a for loop always iterates over a Python object:
Meanwhile, for nearly three decades, C++ supported only C-style for loops. Finally, in C++11, range-based for loops were added:
You can iterate over a std::vector or any class which implements the begin and end member functions – not unlike Python’s iterator protocol. With range-based for loops, I often find myself wishing C++ had Python’s xrange function built-in.
Python has always been a dynamically typed language. You don’t need to declare variable types anywhere, since types are a property of the objects themselves.
C++, on the other hand, is not dynamically typed. It’s statically typed. But since C++11 repurposed the auto keyword for type deduction, you can write code that looks a lot like dynamic typing:
When you call functions that are overloaded for several types, such as std::ostream::operator<< or a template function, C++ resembles a dynamically typed language even more. C++14 further fleshes out support for the auto keyword, adding support for auto return values and auto arguments to lambda functions.
Python has had tuples pretty much since the beginning. They’re nice when you need to package several values together, but don’t feel like naming a class.
C++ added tuples to the standard library in C++11. The proposal even mentions Python as an inspiration:
Python lets you unpack a tuple into separate variables:
You can do the same thing in C++ using std::tie:
In Python, lists are a built-in type. As such, you can create a Python list using a single expression:
C++’s std::vector is the closest analog to a Python list. Uniform initialization, new in C++11, now lets us create them using a single expression as well:
In Python, you can also create a dictionary with a single expression:
Similarly, uniform initialization also works on C++’s std::map and unordered_map:
Python has supported lambda functions since 1994:
Lambda expressions were added in C++11:
In 2001, Python added statically nested scopes, which allow lambda functions to capture variables defined in enclosing functions:
Likewise, C++ lambda expressions support a flexible set of capture rules, allowing you to do similar things:
Python’s built-in filter function lets you selectively copy elements from a list (though list comprehensions are preferred):
C++11 introduces std::copy_if, which lets us use a similar, almost-functional style:
Other C++ algorithms that mimic Python built-ins include transform, any_of, all_of, min and max. The upcoming ranges proposal has the potential to simplify such expressions further.
Python began supporting arbitrary argument lists in 1998. You can define a function taking a variable number of arguments, exposed as a tuple, and expand a tuple when passing arguments to another function:
C++11 adds support for parameter packs. Unlike C-style variable arguments, but like Python’s arbitrary argument lists, the parameter pack has a name which represents the entire sequence of arguments. One important difference: C++ parameter packs are not exposed as a single object at runtime. You can only manipulate them through template metaprogramming at compile time.
Not all of the new C++11 and C++14 features mimic Python functionality, but it seems a lot of them do. Python is recognized as a friendly, approachable programming language. Perhaps some of its charisma has rubbed off?
What do you think? Do the new features succeed in making C++ simpler, more approachable or more expressive?