1. 14
  1.  

  2. 13

    It seems like C++ is the only language where the advice has always been “don’t use the basic language features.” One could argue that the same is true of Javascript but for Javascript it is more like “here are things to be careful about with the basic features.”

    1. 12

      Kind of a strawman. Here’s a modern C++ raw loop:

      for (const auto &element : container) {
          // do stuff with element
      }
      

      This is quite a bit lighter than the old raw loops the article is complaining about, and very widely applicable (every time the container implements iterators, which is almost always). Stuff like std::foreach and std::find_if can be implemented simply enough that we’re not even tempted to reach for the <algorithm>.

      Also, <algorithm> is not blameless either: the input collection is almost systematically described with two iterators, instead of the entire collection. Guess what, we rarely operate over a portion of the collection. Almost every time we say collection.begin() and collection.end() (or the more “modern”, more verbose std::begin(collection) and std::end(collection)). Compare std::find_if() to what it could have been:

      // current API
      auto it_found = std::find_if(std::cbegin(my_vect), std::cend(my_vect), predicate);
      
      // better API
      auto it_found = std::find_if(my_vect, predicate);
      

      People would use <algorithm> more if they didn’t require such unjustified overhead.

      1. 3

        I think that’s the point of ranges and range versions of algorithms in C++20. Took long enough to think of pairing begin/end into a single structure! :)

        1. 1

          I’d say range-based loops don’t count as “raw loops”. I know the article defines raw loops as simply a for loop, but the real problem it tries to avoid is related to the for(;;) form, which is prone to off-by-ones, and allows complex loop conditions and fiddling with the iteration variable. A simple for-each loop has none of these issues.

          1. 1

            I understand, but by omitting range for, the author posited a false dichotomy. It felt a bit like we were stuck in pre-C++11 era (and back then <algorithm> were unusable because there was no way to put the body of the loop where it belonged).

        2. 6

          I don’t do this, mostly because STL algorithm syntax is so very ugly and verbose. (C++20 is going to fix this, whenever it becomes stable enough for me to use.) The other reason is that I often use my own collections that don’t follow STL conventions, for the same reason.

          1. 6

            One of the many curses of C++ (and, specifically, one of the curses befalling C++ documentation and learning resources) is that so many bad things happen when industry consultants and/or language fanboys get a language that also tries to preserve backwards compatibility with C.

            As @mfeathers already noted, C++ is one of those peculiar languages that have a seemingly endless list of “don’t use [basic language feature]/[standard library feature]” articles and blog posts. Normally, that raises the largely rhetorical question of “why is it shipping with the language if you’re not supposed to use it??”. In C++‘s case that’s not exactly a rhetorical question though: most of the time it turns out said thing is there for compatibility with either C or a previous C++ standard.

            Unfortunately, this turns many seemingly good pieces of advice – including this one – into really bad ideas for non-trivial projects older than a few months, or projects that use a substantial number of external libraries. Sooner or later you’re going to run into, and import into your codebase, a bunch of code that uses whatever loop style is considered a faux pas in C++-$year. I’m sure that’ll be bad for whatever reason apply in $year or $year + 2 or whatever, but there are things worse than that, including code that religiously uses two loop styles, which is what these situation invariably devolve into.

            The impact of this kind of blog post is magnified in C++ land because it’s such a huge language and it changes quite frequently for something that big. Even experienced programmers who use it every day have trouble keeping their understanding in-depth and up-to-date . So a lot of C++ users end up defaulting to whatever piece of advice they read last week on blogs like Belay C++, resulting in a lot of style that’s driven by hype and hustle rather than real community conventions. It’s really annoying to interact with (for me, it’s one of the big reasons why I stopped doing any C++ contract work).

            1. 3

              This is where I break from the “modern C++” community.

              Some of the algorithm functions are great for very targeted things, like find_if and copy_if. However, many articles I read about using STL algorithms to “simplify things” end up writing terse but exceptionally dense and nested algorithms of multiple composited functions when a straightforward implementation with range-based loops would be much more clear.

              I also disagree with casually writing templates as there are many nuances with templates which can introduce subtle bugs or inefficiencies which might not be noticeable until reused later with different types.

              1. 1

                The author is encouraging people to use the algorithms library from the STL instead of rolling their own.

                What confused me for a while is that they used the word “algorithms” instead of saying “STL Algorithms library” and they kept on about “raw loops”.

                Folks, there is nothing wrong about writing your own implementations of things (“raw loops”). If you find the STL is convenient for you, use it. Indeed there are cool algorithms in the STL, but often their usage is strange and awkward, like putting on clothes that fit just a little off. I often end up just writing my own which has syntax better fitted to my use case.

                1. 4

                  I thought the article was about the importance of preparing raw loops to avoid contracting the dreaded loopworm…

                2. 1

                  I made this as a personal challenge about 15 years ago (before c++11) after i learned Haskell. I got pretty far along before i had to cave in because some data arrived in two separate lists but were related as if they were a single list of tuples. That’s when things became less elegant to mess around with. Also, native schemes like python enumerate() or haskell’s zipWith \x [1..] are elegant ways to introduce counters.