4 ms·
In current C++, lots of std functions are annoying because you need to give both .begin() and .end(), while in 99% of the cases when using a C++ container you w
by Aardwolf 8y ago
In current C++, lots of std functions are annoying because you need to give both .begin() and .end(), while in 99% of the cases when using a C++ container you want to do your algorithm on the whole container (a function with 2 parameters is good to have for the other 1% of cases and the case of 2 pointers of course).
What took so long and why are "ranges" needed for that? Most other languages have sort, transform, ... with a single parameter (such as a container or array), and those don't require something called "ranges" for that.
Why couldn't C++ at least already have long had convenience functions that just take a container and do the .begin() and .end() for you?
I'm all for having "std::transform" and stuff, but if it requires you to type just as much as writing it manually with a for loop due to having to type the name/expression of your container twice, what's the point.
EDIT: oh, and it's going to be std::ranges::sort(v) instead of just std::sort(v)? What's wrong with naming it just std::sort(v)? Do C++ users really need to be reminded it took a "ranges" concept just to sort a simple container every single time they'll use it?
- repsilat 8y agoI agree. The "flexibility" of being able to operate on a subset of the container was never a good argument, because you could trivially make a "view"/slice template type to fake begin/end to any pair of iterators. Make the common case short and the uncommon case possible.
- saagarjha 8y agoRanges unify C arrays and C++ standard library types in a rather elegant, general purpose way. Though, I’m still of the opinion that every function that takes a range should also be overloaded to operate on the whole container as well (and my personal C++ “library” does this already).
- int_19h 8y ago> because you could trivially make a "view"/slice template type to fake begin/end to any pair of iterators. In C++, that was not trivial at all. Implementing a custom container with iterators (which you'd have to do for this - you can't just propagate iterators as is) is very verbose, since there's no syntactic sugar for it, like say generator functions in Python.
- MaulingMonkey 8y ago> why are "ranges" needed for that? They aren't, but without ranges, things that accept iterators are more general than things that accept only containers (e.g. you can't iterate over half a container without a range, iterators, or copying to another container through other means defeating which would defeat the whole point.) As such it makes sense to have a generic range type first, then algorithms that operate on containers/ranges. Additionally, if you can take a range<Iter> instead of a Container (I haven't even checked if C++20 algorithms do), you might get better error messages (e.g. "Xyz cannot be converted to a range" instead of "Xyz doesn't implement begin()"). > What took so long Everything takes long in C++ standards land. I have no special insight into the actual workings of the standards committee, but I've always chalked it up to a combination of being extremely conservative about changes, made worse by past missteps burning them, and less than ideal foundations which already made C++ hard to parse, slow to compile, and inconsistent across compilers, and often not fully implemented. It's not like there's been some giant technical hurdle across the board - boost::range has been around for well over a decade (in boost since 1.32.0 in 2004). Faster iterating languages usually have a fresh start unencumbered by backwards compatibility concerns with large existing codebases, less cruft inherited from other languages (cough C cough), and a single official implementation which can be used to more quickly prove out good ideas and discard bad ones.
- Aardwolf 8y ago> They aren't, but without ranges, things that accept iterators are more general than things that accept only containers (e.g. you can't iterate over half a container without a range, iterators, or copying to another container through other means defeating which would defeat the whole point.) Yes but they could have provided both a single-container-parameter version and a two-iterator-parameter version of all those functions like sort and transform. Templates and SFINAE support that, and the single parameter one would call the two parameter one with .begin() and .end() for you. They should try to make the std library such that you type shorter code, not longer code, imho: longer expressions are less readable. But well, it looks like ranges mostly do that for the user side (except that it uses std::ranges:: instead of just std:: as prefix) so at least that's nice.
- adgasf 8y agoC++ standardized on ranges, but in my experience enumerables (or sequences) are the more common case in real applications. You might find this intriguing https://github.com/LoopPerfect/conduit https://github.com/LoopPerfect/conduit
- erichocean 8y agoThank you!
- int_19h 8y agoRanges are nothing more than bounded enumerables (iterables in C++ parlance). An unbounded enumerable would be represented by some way to obtain a forward-only iterator - also an existing C++ idiom.
- eric_niebler 8y agoWhy it took so long is that: (a) C++ is an international standard, has a huge installed base of business- and mission-critical software, probably billions of lines of code, tens of millions of programmers, and we can't afford to get things wrong (though we still do sometimes). (b) Nobody has built a large, _very_ generic, general purpose, high-performance library, on top of the (also new) C++ concepts language feature before. We were figuring it out as we went. (c) While standardizing this piece, we were also thinking 5 to 10 years down the road and trying to make sure what we were standardizing now would evolve well. For instance, we already know pretty well what using ranges with coroutines will look like (i.e., reactive streams). We already know what other lazy range adaptors we want, and we know they work with the bits we're getting for C++20. We know how to integrate eager adaptors that transform containers and compose. This all needed to be built, tested, and well-understood. As for why it is `std::ranges::sort` instead of `std::sort`, this exercise wasn't just about adding overloads that take ranges instead of iterators. It was also about rigorously specifying in code what the requirements of each algorithm are. For Reasons, we can't just slap new requirements on old algorithms that have been shipping for 20 years. It will break mountains of code. Nobody likes having two `sort` algorithms in two different namespaces. It is preferable to the alternative.
- saagarjha 8y agoI’m still not getting your argument. Why is this not “just adding overloads”?
- kbsletten 8y agoSounds like they wanted to be a little more aggressive rather than just putting lipstick on that same pig. By specifying the new method they can clean up the rough edges for performance or ergonomics without breaking existing code.
- CJefferson 8y agoHere's one case that is tricky to get right in c++. At the moment you can call sort(x,y) to sort a range, or sort(x,y,z) to give a comparator. If we allow sort(c) for a container, is sort(c,z) sorting a container with comparator, or a range? It's surprisingly hard to get this right with templates, without concepts.
- wrsh07 8y agoA few points: If you don't want to deal with begin/end, there are lots of utility libraries, and there's not much reason to standardize it. For example, here is Google's wrapper library (disclosure: my employer) that takes "just the container": https://github.com/abseil/abseil-cpp/blob/master/absl/algorithm/container.h https://github.com/abseil/abseil-cpp/blob/master/absl/algori... Regarding your edit: it's pretty simple in c++ to alias namespaces as needed for your project. The standards committee is working with a big install base, and they have a few hard requirements. They don't break the ABI. They try not to break calling code in other ways. (Adding overloads while client code passes around pointers to your functions can have surprising effects - perhaps causing their code to stop compiling? Pretty sure one of abseil's requests is that clients don't take addresses of their functions for this reason Stack overflow on taking addresses of overloaded functions: https://stackoverflow.com/questions/2942426/how-do-i-specify-a-pointer-to-an-overloaded-function https://stackoverflow.com/questions/2942426/how-do-i-specify... Abseil compat guidelines: https://abseil.io/about/compatibility https://abseil.io/about/compatibility)
- jcelerier 8y ago> Why couldn't C++ at least already have long had convenience functions that just take a container and do the .begin() and .end() for you? It's just a boost header that you can use which does exactly this : https://www.boost.org/doc/libs/1_69_0/libs/range/doc/html/index.html https://www.boost.org/doc/libs/1_69_0/libs/range/doc/html/in... It's your problem if you haven't been using it.