back

by TremendousJudge·3y ago·view on hn ↗
Half of the new features of "modern" C++ editions leave me agreeing with the change but wondering what they were thinking before. Another example: std::map::contains was introduced in C++20; why did they go decades thinking it wasn't necessary to have such an operator (instead providing only count() even though a map has unique keys), and why did they change their minds only now? Did the old guard literally die off or something?
3 comments
The historical lack of sequencing is because they were unsequenced in C, and C++ thus inherited it.

And yes, it does seem that there were a lot more people hell bent on resisting correcting unnecessary UB in the past than today, but they’re still around.

I get it, but then, why change it now? (or 6 years ago I guess)
Sorry, I had an unsaved edit above. It seems the resistance to removing unnecessary UB has reduced over the years.
Problem with contains is we are now going to see more code like

    if (map.contains(foo)) {
       bob(map[foo]);
    }
over the (vastly uglier) more efficient:

   if (auto it = map.find(foo); it != map.end()) {
       bob(*it);
   }
Of course languages like C# manage this in a more elegant way with out parameters declarable at the call site.
A pity the c++ compiler has no way to recognise calls to the c++ library in order to do rewrites like that automatically. It's CSE at the stdlib level, should definitely be possible to do that.
Hard coding behavior like for the STL that seems pretty questionable, especially given that std::map and std::unordered_map have poor performance compared to other alternatives (e.g. absl::btree_map and absl::flat_hash_map, and likewise folly has better implementations).
if let is such a nice way to express this

    if let Some(x) = map.get(foo) {
        bob(x)
    }
One subtle but noteworthy thing is that the idiom only mentions map by name once, which is nice if you have a very long map name, and prevents copy paste bugs where you only update one of the two mentions.
This pattern exists in C++ as well. The specific issue here is that all these STL APIs are in terms of C++'s iterator model, and can't be replaced with a more modern "optional" style that allows this cleaner coding style :-/
Scala:

    for (x <- map.get(foo)) {
      bob(x)
    }

    // or

    map.get(foo).foreach(bob)

    // or

    map.get(foo) match {
      case Some(x) => bob(x)
    }

  std::map::find (item) != map.end()  <=> std::map::contain (item)
I think the problem is that with `std::map::find(item)` you get the value back but you don't with `std::map::contain(item)` - which means a second lookup to actually retrieve the value, no?