In contrast, for most other use cases, C++ streams are slow. But, on the plus side, at least they’re hard to use.
If there’s one bit of the C++ standard library that I’d like to set fire to and then scatter the ashes over a wide area, it’s the streams abstraction.
I just can’t get over the WTF of overloading the shift operators. I know it’s just a bikeshed complaint and very shallow of me, but still. Why???
It wouldn’t be such a WTF in isolation. Shift looks kind-of like a pipeline, so it is a bit plausible. It’s a complete WTF when combined with the precedence rules. From memory, could you say what this means?
std::cout << a + b << c || d;
+ is higher precedence than <<, but | is lower precedence, and so this will add a to b, write that to cout, then write c to cout, then bitwise or cout with d. The last of these is probably a type error.
It’s only vaguely sensible because most of the streams don’t support implicit coercion to any type that can work with other operators (so things that look like they should work fail to compile, rather than doing something very surprising).
Like so much of C++, it’s a design decision that makes sense only if you fail to consider any wider context and how it might interact with the rest of the system.
You think that’s wild, have you ever seen or used the Python SDK for Apache Beam?
counts = (
| 'split' >> (beam.ParDo(WordExtractingDoFn()).with_output_types(str))
| 'pair_with_one' >> beam.Map(lambda x: (x, 1))
| beam.WindowInto(window.FixedWindows(15, 0))
| 'group' >> beam.GroupByKey()
| 'count' >> beam.Map(count_ones))
The Gentle Tyranny of Call/Return
Using call/return to express all other architectural styles invariably leads to…“interesting” results.
Semi-indirectly discussed on Lobsters as https://lobste.rs/s/alzaim/thoughts_on_gentle_tyranny_call_return
I saw this recently. I think we’ll be using Beam soon at my work, our sense is that it is better for “interesting” map/reduce than the other options we are aware of. But this syntax strikes me as overly clever.
It’s jarring at first. I’ve written some Beam pipelines and honestly it’s a lot more elegant in Python because of this cleverness. The Java SDK is…not bad…but the Python one felt (to me) surprisingly nice.
I asked a question on Stack Overflow about this topic during one of my failed attempts to learn C++ and the answers convinced me that either I was never going to understand streams or C++. I decided C++ was not for me.
Don’t judge the rest of C++ by streams. Part of the reason streams are so painful to learn is that they don’t behave at all like anything else in the standard library, or like other idiomatic C++ code.
If you grep the C++ standard library for ‘virtual’, you find that the vast majority of uses of that keyword are in the streams part. A few things (shared_ptr, function, some of the locale things) use it internally to implement type erasure. Regex uses it as an implementation detail. Nothing else in the standard library defines interfaces that you must implement using inheritance and overriding virtual functions.