Subject: Re: [boost] [optional] operator<(optional<T>, T) -- is it wrong?
From: Gavin Lambert (gavinl_at_[hidden])
Date: 2014-11-30 18:22:07
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".)