On 1/12/2014 16:57, Matt Calabrese wrote:
On Sun, Nov 30, 2014 at 5:49 PM, Gavin Lambert
wrote: Most containers do not implement ordering relations of the container itself.
Yes they do. All of the standard containers provide lexicographical ordering.
I stand corrected. I must admit to being unaware that these existed; I think I missed them in the C++ library docs I was looking at as they listed non-member functions in a completely separate location. Perhaps that does undermine some of my arguments. :)
As for why one might take advantage of such an ordering? I already gave you an example in this thread where I personally used the ordering of variants, though you mysteriously ignored it and again are make a claim that ordering is simply "meaningless." I have more examples if you want, since I actually use variants and tuples pretty much every day. So is ordering meaningful? Of course it is. It is in my concrete example and it is in more abstract, generic code where tuples and variants tend to manifest themselves either internally for storage or when producing results. As someone who actually uses these types in practice and who uses ordering of them, I am flat out telling you that ordering them is, in fact useful, and it does, in fact, make sense.
Perhaps "meaningless" was the wrong word. I meant something closer to "unobvious", as in the ordering relationship is less visible to a casual reader of the code, and could be easily misinterpreted or broken by a future programmer. Still, I suppose that's what unit tests are for (when they actually exist).
That said, why do you think that it would be hard to remove the ordering once present? If order here were /actually/ meaningless as you repeatedly claim, then it would trivial to remove, since nobody would be using it in meaningful code.
If a library has defined operator<(T,T), then that operator exists and there is (as far as I am aware) no way to remove it short of editing the library code. Conversely if the library has not defined the operator, there is nothing (bar namespace etiquette, perhaps) preventing the application from doing so itself, as long as it doesn't need private data to do so. I suppose that could be resolved by an application that really wants to get rid of the ordering relation defining a new class that delegates the original and mirrors its interface apart from that group of methods/operators, but this seems like a massive headache for everybody and doesn't really solve unintended mixups.
The thing is, absolutely none of this talk of requirements really applies here, though, since as I pointed out, the ordered and unordered containers are completely different datastructures and so comparison of their requirements is misleading. In the case at hand, the types /can/ be ordered, so whether or not those types have a /default/ order should have no bearing on whether you use an ordered or unordered set. Both of those choices are perfectly valid and the decision to choose one or the other has nothing to do with defaults.
As I said, the idea was that while you *could* define a default sort,
that would be surprising in many cases (eg. given a variant
No, people were misusing /operators/ not std::less -- particularly the mixed-type operators. We are not talking about operators here as I've tried to restate in several replies just to be clear. We are talking about default ordering for a type (I.E. specifying a std::less specialization or some proposed std::order).
I'm not sure I want to live in a world where std::less wasn't equivalent to operator<, where the latter exists. (At least at the library layer; if the application wants to mess with it that's their own business.)
My generalisation was that even op< on two optional<T>s is suspicious as some people don't seem to agree where "none" sorts, or even what "none" means in some cases -- and because others were arguing that it was inconsistent to define one op< without the other.
Here's where I tend to disagree (I'll go back to talking about order in general, though, so that we don't get derailed regarding operators that should or should not exist). Specifying ordering for any type at all is always a subjective decision. If someone sees an order comparison with an optional, no matter how that function is spelled, should that programmer A) make an assumption about ordering and not look it up or B) look up the ordering? Whether the function is spelled operator< or std::less or std::order seems unimportant to me in that particular respect. In every one of those cases the programmer would have to look up what the order is if they wanted to use it in a specific way. Because of that, I don't think it's a valid rationale to exclude the function. You always need to know what any function does when you use it. A default ordering function isn't particularly special.
The case in question is where you were using it without realising it; in the stated example perhaps when code that used to have int parameters was changed to optional<int> without amending the operator use accordingly. That's a programmer error, of course, but it would have been nice if it were also a compiler error. (Sometimes it's less obvious, when there are layers of typedefs and metafunctions in the way, especially when these come from external code.) Admittedly the compiler can't catch everything and it's a philosophical question on how much "hand holding" the library should do to help avoid mistakes, but this question did arise in the context of making a "safer" API for optional. Perhaps I ran too far with the ball, but sometimes that's how you learn where the lines in the sand are. (Have I mixed enough metaphors yet?)