I have come to the conclusion that part of the reason python is so fun is because it is slow.
There are so many lovely and easy to use libraries in Python. I took a couple and tried to be inspired by them to write a C++ library, maybe for addition to boost.
However, if you are writing C++, people expect your library to be fast and memory efficient -- you can't go around sticking the entirety of a parsed file in a std::string. Also, people then start saying your code better interoperate with their templated classes well, and they want to replace the memory management entirely, and it goes on...
Of course, the resulting libraries are very fast and very clever, but they have lost the joy. They also take much longer to write, maintain and use.
Watch out for conflating abstraction level with speed. Coding at a low level of abstraction means sweating the small stuff, but it's easy to fool yourself into thinking you're making things fast - when actually, you're micro-managing.
Painting with broader brushstrokes with less concern for micro-efficiencies lets you block out a solution faster. Another part of the problem with C++ is that the components come with so many rough edges that need to be filed down that you can't help getting swamped in a certain level of detail, unless you start with a large toolbox or framework that lets you work back at a higher level again.
You ought to have the equivalent of Java's file stream, buffer and text decoder as three separate bits that you can compose, so that putting a whole file in a string is never even a temptation. But if you start out with a sparse toolbox, it's a slog.
On the other hand, there were times when I had to get a piece of paper and draw diagrams to construct a twenty-line sequence of numpy calls, when the same would have been achieved by several completely straightforward double (or triple) loops in C++. Writing the same loop in Python was out of question because it would be too slow.
One of my clients recently replaced a major chunk of their C++ code with Python and achieved a speedup from multi-hour to sub-millisecond. That's a big win.
Python encourages readable code, which enables smarter algorithms, which ultimately swamps all those little memory optimizations. Oh, and PyPy/Numba/Cython let you get those little optimizations, too.
In addition to that there are loads of libraries for Python which are written in C, which gives you speed in the right moments.
I think the readable code thing is really really important, too. I can understand other peoples code quicker and learn more about the actual algorithm unlike in C++ where I wonder half of the time about syntactical non-sense and optimizations for certain compiler targets.
Then again, Python and C++ target very different groups and I like both languages for certain things.
> One of my clients recently replaced a major chunk of their C++ code with Python and achieved a speedup from multi-hour to sub-millisecond.
I'd really like to know what they were doing and how they could do it so wrong that the C++ version took hours while the Python version was faster than a blink of the eye.
Good question. I did have a situation where looping over a fairly large Pandas dataframe took 12 minutes, but using the underlying numpy values took only 3 seconds. The looping was required to do complicated row and column operations.
Similarly, naybe the C++ code was using an inefficient data structure for a large dataset compared to using something like Numpy.
It had to do with the number of dimensions and combinations that were being looped over. That kind of scale difference generally comes from combinatoric explosion -- exponential or high polynomial time vs linear or log-linear time.
The rewrite realized an approximation was reasonable in place of a more "correct" algorithm.
Note that I'm not saying Python was the cause, but the ease of reading and writing code may have helped the programmer come to this algorithm. Instead of stressing about bugs and deadlines. Algorithm choice seems correlated with language choice, in my experience.
> One of my clients recently replaced a major chunk of their C++ code with Python and achieved a speedup from multi-hour to sub-millisecond.
Code rewrites are often more than a literal translation. They often eliminate old code, and allow to rethink the architecture. So it's really not a surprise that Python code would be faster here. A rewrite to C++ would probably be much faster still.
Perhaps a C++ rewrite would be faster, but it depends on how many of the dependencies you revise to be optimal for this particular task and how much more clever you are than the NumPy authors and a jit-compiler.
C++ may let you "squeeze every bit of performance," but in a lot of cases it does so by handing you a lot of rope.
You might use it to make a rope bridge across that performance gap, but how good your bridge is depends a lot on you - and if you just manage to hang yourself with it, well, that's on you as well.
With Python it may take longer to get across because you detour a mile over to a more solidly constructed bridge, but you still get there and for most cases you get there fast enough.
"you can't go around sticking the entirety of a parsed file in a std::string"
Sure you can. C++ is at best programmed like python. Just throw the working first version together - and once you hit a performance gap, you can optimize it.
Using a profiler.
Premature optimization is mostly pointless because for most non-trivial performance critical apps the bottleneck wont be where you expect it.
The faster you find the actual problematic hotspots with production content the better. The way to get there fast is to treat C++ like filthy python.
Don't trust anyone trying to goad you into premature optimization unlesa they understand the specific problem you are trying to solve, and only then with skepticism.
Well, in my own code I would, but you would never get some file handling / parsing library into boost, or the standard, that did that. And then (another C++ issue), installing libraries can be fiddly.
"but you would never get some file handling / parsing library into boost, or the standard, that did that."
Why would anyone want to write code that would go into either of those? In the general sense, I mean.
Good production code is simple and is implemented preferably verbosely and understandably than cleverly.
Speaking of good software patterns, I'm not sure boost nor STL are great examples of good software architecture. Boost especially is very templatey-bloatey. The biggest merit of STL is that is exists.
"installing libraries can be fiddly."
Does anyone really need to do that? Install C++ specific libraries I mean. In 10+ years I've never developed C++ software that would not store all of it's dependencies part of the project hierarchy or sub-structure, except for the standard library.
The worst part of C++ is that is has these warts that subtly guide developers into copying all sorts of patterns for their own sake because they are seen "as the standard way to do it". Object orientation and templates should not be considered the basic building blocks of the archictecture of a C++ program, but rather escape valves when some usage pattern would end up more complex without them.
For example, when someone spends long production time creating an elegant template based solution for whatever, generally it is an indication that something is wrong somewhere. There are of course exceptions to this rule, but just saving some boilerplate is never a good reason to do it.
The STL is a library of common algorithms and data structures that are decoupled from one another, and the complexity of operations in the STL has been enshrined in to the C++ standard. These two achievements alone warrant granting it huge respect. Imho, it's the essence of great design and it should be the very first thing taught to programmers new to C++.
> copying all sorts of patterns for their own sake because they are seen "as the standard way to do it".
Yeah, Python programmers would never do anything like that. If they did they might all run around calling it being 'Pythonic' or something.
> Object orientation and templates should not be considered the basic building blocks of the archictecture of a C++ program
Just tools in the toolbox, and the amount of mileage you can get out of just these two features, along with other staples like RAII and function overloading is pretty astounding.
Part of it is just that Python has an awesome, supportive community. Sounds like the C++ community is kinda critical and demanding, in your experience.
C++ pushes you to conflate optimization with the higher level meaning of what you're trying to implement. In Python you can write the higher level meaning in a more 'pure' way, which is fun of course. The really interesting question is if you can program at the higher level while still running fast, perhaps by specifying optimizations separately?
There are so many lovely and easy to use libraries in Python. I took a couple and tried to be inspired by them to write a C++ library, maybe for addition to boost.
However, if you are writing C++, people expect your library to be fast and memory efficient -- you can't go around sticking the entirety of a parsed file in a std::string. Also, people then start saying your code better interoperate with their templated classes well, and they want to replace the memory management entirely, and it goes on...
Of course, the resulting libraries are very fast and very clever, but they have lost the joy. They also take much longer to write, maintain and use.