On Wed, Nov 26, 2014 at 6:49 PM, Gavin Lambert
On 27/11/2014 11:03, Gottlob Frege wrote:
tl;dr: I'd support dropping op< and only having ==, !=, and std::order/std::less.
TBH, other than the "existing code" issue I'm not sure I like the idea of std::less working but op< not -- and in particular if you don't agree with the idea that "none is less than any other value" then I don't know why you'd agree with the idea that it should sort that way in a map, which is what you appear to be suggesting.
I don't like that std::less isn't the same as op< either, but it is
the best we currently have. I hope to propose a fix for that -
something like std::order, which map and set would use instead of
std::less (and std::order would default to std::less for backwards
compatibility).
A good example of where std::order shouldn't be the same as op< would
be std::complex. There isn't a sensible/natural mathematical way of
answering whether one complex number is larger than the other (while
at the same time getting the other properties we commonly expect from
a less-than).
So std::complex shouldn't have op<. But it would be nice to use them
in maps and other algorithms. (Sure, we now have unordered_map, but
map/set still has uses.)
And std::complex, looked at as a pair
Perhaps std::less should not support it either, but std::hash should, and if you want to use optional keys then you have to use std::unordered_map instead?
But why do you want to have optional keys anyway? When does it make sense to have a single value attached to an empty key? It's rare for a dictionary type to permit null keys in any language.
optional<T> is Regular if T if Regular. The more that optional<T> "just works" like int works, the better. Particularly for generic code.
OTOH, I don't have any personal problems with op<(optional<T>,optional<T>) existing and with its current behaviour, other than the apparent disagreement about where "none" should sort (and I don't have any issues with the library author having defined this as "less", though apparently others do).
I'm less convinced of the merit of op<(optional<T>,T), as the reality is that in *real life code* this is most likely to be a coding error rather than something intentional. Perhaps this is just a failure of imagination, but other than toy examples I cannot imagine a case where someone would use this intentionally. I'm not sure I'd go as far as advocating that they be explicitly removed or poisoned, but I suspect that this would improve overall code quality without unduly burdening people who do want to make this comparison.
I am absolutely convinced of the merit of implicit optional<T>(T) construction and assignment, and op== working for both, and would regard it as a bug if these were removed.
I agree with the implicit constructor. For less-than we have these competing points, (that each of us may weigh differently) 0 - std::less should be same as op< (I think we all agree here, actually, which is why we should have std::order) 1 - op<(optional<T>, optional<T>) is "sensible" but somewhat arbitrary 2 - op<(optional<T>, T) is questionable, often (usually?) wrong 3 - in general, func(optional<T>, optional<T>) should work if passed T's (ie implicit conversion is important) 4 - op<(optional<T>, optional<T>) *is* of the form func(optional<T>, optional<T>) - ie why should it be different? 2 and 3, to me, are the strongest, but directly opposed. How do you solve that? Either say A1. "well operators are special, not typical functions" so we can poison them while keeping general functions implicit A2. 1 is on shaky ground, so let's remove both 1 and 2, but keep std::less/std::order, which was the main reason for having op<. I can live with either answers. They both sound reasonable to me. Tony