Comparison between compile-time string and std::string behaves unexpectedly
- Dominant language
- C++
- Stars
- 1.9k
- Forks
- 225
- PR merge metrics
- No merged PRs in 30d
Description
The following code has a very unexpected behavior:
```c++
#include
#include
#define BOOST_HANA_CONFIG_ENABLE_STRING_UDL
#include
#include
using namespace boost::hana::literals;
using namespace std::literals;
int main() {
assert(boost::hana::equal("x"_s, "x"s)); // assertion fails
}
```
The problem here is that since `"x"_s` is a compile-time string (`hana::string`) and `"x"s` is a `std::string`, which have nothing in common (no common type, no conversion, etc.), Hana says they are not equal (instead of giving an error, for example). The rationale is documented in [`Comparable`'s documentation](http://boostorg.github.io/hana/group__group-Comparable.html):
> In the context of programming with heterogeneous values, it is useful to have unrelated objects compare false instead of triggering an error. For this reason, equal adopts a special behavior for unrelated objects of tags `T` and `U` that do not satisfy the above requirements for the cross-type overloads. Specifically, when `T` and `U` are unrelated (i.e. `T` can't be converted to `U` and vice-versa), comparing objects with those tags yields a compile-time false value. This has the effect that unrelated objects like `float` and `std::string` will compare `false`, while comparing related objects that can not be safely embedded into the same super structure (like `long long` and `float` because of the precision loss) will trigger a compile-time assertion. Also note that for any tag `T` for which the minimal complete definition of `Comparable` is not provided, a compile-time assertion will also be triggered because `T` and `T` trivially share the common tag `T`, which is the expected behavior. This design choice aims to provide more flexibility for comparing objects, while still rejecting usage patterns that are most likely programming errors.
This special behavior of comparing `false` for unrelated types usually works as intended, except when it does not. One _possible_ solution would be to check whether `T` and `U` are `Comparable`, and if so, then compare them when writing an algorithm. It _might_ make algorithms more complex to write, although one could provide a helper function that does that.
Thanks to @Quuxplusone for finding this out.
Contributor guide
Research direction
Start with boost/hana/string.hpp and boost/hana/equal.hpp, then read the Comparable documentation linked in the issue. Reproduce the minimal C++ example and determine the intended policy for comparing hana::string with std::string; done requires an agreed behavior and regression coverage for this case.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100