On 28/11/2014 21:37, Matt Calabrese wrote:
Why? I've heard this stated before regarding ordering and frankly I think it's nonsense. Whenever you design a library you're going to make choices that don't have an objective correct or incorrect option, even separate from the issue of ordering. This can be anywhere from simple things like naming or parameter order to the higher-level semantics of your types. The library developer frequently makes subjective decisions and that's perfectly fine -- I'd even say it's a good thing. The fact that there are multiple valid solutions does not at all imply that you should avoid choosing any of them, especially in this case where we are talking about a default that doesn't even have to be used. If, in the case of a default ordering, that default isn't what's desired for a specific situation, then the user can just be explicit there. Do you have a problem with the fact that tuples have a default ordering? What about strings? These are not problematic in practice, nor, I'd argue, are they problematic in theory.
Strings are ok -- ordinal ordering is a reasonable default, though admittedly sometimes other orders need to be selected by the application. But this is fine as is. If tuples have a default ordering (I'm not sure, because I haven't used them), then yes, I would regard that as a bug.
Okay, so what happens if you reverse the situation and don't provide a default ordering: First, people can no longer use the type in datastructures like sets unless they provide an explicit ordering, even if they don't care what the ordering is. So here the user needs to do more to accomplish the same end result. What exactly does the user gain?
This is because they are using the wrong data structure. It *should* fail because there is no sensible default ordering for tuples or optionals or variants. In which case they should take the hint that they should be using an unordered container instead, such as unordered_map or unordered_set.
Now, flipping things around, what would happen if the library designer said "I don't want to choose a default"? As a user of the library, the only effect is that I now need to do more work to accomplish my same goal for any place that can take advantage of a default ordering. What exactly is the tangible benefit here?
For one thing, it makes your code immune to a change in the default ordering as a result of a library upgrade or switching to a different type (eg. when switching from boost to std, if these made different choices). For another, it makes you actually think about what you're doing, and whether you actually *want* ordering.
Defining op< for containers was a necessary evil while std::map was the only standard associative container, and it happened to require ordered keys. Now that unsorted associative containers exist (std::unordered_map and its Boost equivalent for pre-C++11), I don't think its existence can be justified any more.
WHAT!? The choice of whether to use an ordered or unordered associative container should have nothing to do with this. Period. They are entirely different data structures with different complexities and the issue of defaults is entirely orthogonal. However, while we're on the subject, I think it's really important to point out that the unordered containers are also taking advantage of a default that by your, and others', logic, shouldn't exist -- the default hash. Just like with ordering, there is any number of equally valid hashes that can be associated with a given type. Why is one better than any other? I don't see why anyone would say that it doesn't make sense to have a default ordering but yet it does make sense to have, and rely on, a default hash.
Hashes are an equality relation, not an ordering relation. It's a completely different thing. I have no problem with (and in fact strongly advocate) having equality work for tuples, optionals, and variants. And nowhere did I say that the application author *couldn't* use an ordered container if they wish. I'm just saying that those particular types, as key types, should *not* have a default order relation (as there is no meaningful definition of one -- anything is entirely arbitrary), and so while authors should *prefer* to use unordered containers, if desired they can use an ordered container by defining the desired ordering explicitly themselves. (Which might mean writing an ordering function themselves or it might mean simply specifying which ordering function provided by the library should be used. But that function shouldn't be "std::less".)