The Comparable concept defines equality and inequality.
Intuitively, Comparable objects must define a binary predicate named equal that returns whether both objects represent the same abstract value. In other words, equal must check for deep equality. Since "representing the same abstract value" is difficult to express formally, the exact meaning of equality is partially left to interpretation by the programmer with the following guidelines:
equal value.4/8 should be equal to an object representing a fraction as 2/4, because they both represent the mathematical object 1/2.Moreover, equal must exhibit properties that make it intuitive to use for determining the equivalence of objects, which is formalized by the laws for Comparable.
equalequal is defined, not_equal is implemented by default as its complement. For all objects x, y of a Comparable tag, equal must define an equivalence relation, and not_equal must be its complement. In other words, for all objects a, b, c with a Comparable tag, the following must hold:
hana::integral_constant, hana::map, hana::optional, hana::pair, hana::range, hana::set, hana::string, hana::tuple, hana::type
Two data types T and U that model the cross-type EqualityComparable concept presented in N3351 automatically model the Comparable concept by setting
Note that this also makes EqualityComparable types in the usual sense models of Comparable in the same way.
Let A and B be two Comparable tags. A function \(f : A \to B\) is said to be equality-preserving if it preserves the structure of the Comparable concept, which can be rigorously stated as follows. For all objects x, y of tag A,
Equivalently, we simply require that f is a function in the usual mathematical sense. Another property is injectivity, which can be viewed as being a "lossless" mapping. This property can be stated as
This is equivalent to saying that f maps distinct elements to distinct elements, hence the "lossless" analogy. In other words, f will not collapse distinct elements from its domain into a single element in its image, thus losing information.
These functions are very important, especially equality-preserving ones, because they allow us to reason simply about programs. Also note that the property of being equality-preserving is taken for granted in mathematics because it is part of the definition of a function. We feel it is important to make the distinction here because programming has evolved differently and as a result programmers are used to work with functions that do not preserve equality.
The equal and not_equal methods are "overloaded" to handle distinct tags with certain properties. Specifically, they are defined for distinct tags A and B such that
A and B share a common tag C, as determined by the common metafunctionA, B and C are all Comparable when taken individuallyis_embedding metafunction.The method definitions for tags satisfying the above properties are
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.
Variables | |
| constexpr auto | boost::hana::comparing |
Returns a function performing equal after applying a transformation to both arguments. More... | |
| constexpr auto | boost::hana::equal |
Returns a Logical representing whether x is equal to y. More... | |
| constexpr auto | boost::hana::not_equal |
Returns a Logical representing whether x is not equal to y. More... | |
|
constexpr |
#include <boost/hana/fwd/comparing.hpp>
Returns a function performing equal after applying a transformation to both arguments.
comparing creates an equivalence relation based on the result of applying a function to some objects, which is especially useful in conjunction with algorithms that accept a custom predicate that must represent an equivalence relation.
Specifically, comparing is such that
or, equivalently,
Comparable concept.Given a Logical Bool and a Comparable B, the signature is \( \mathtt{comparing} : (A \to B) \to (A \times A \to Bool) \).
|
constexpr |
#include <boost/hana/fwd/equal.hpp>
Returns a Logical representing whether x is equal to y.
The equal function can be called in two different ways. First, it can be called like a normal function:
However, it may also be partially applied to an argument by using equal.to:
In other words, equal.to(x) is a function object that is equivalent to partial(equal, x). This is provided to enhance the readability of some constructs, especially when using higher order algorithms.
Given a Logical Bool and two Comparables A and B that share a common embedding, the signature is \( \mathtt{equal} : A \times B \to Bool \).
| x,y | Two objects to compare for equality. |
#### Rationale for the arity of
equalIt is a valid question whetherequalshould accept more than 2 arguments and have semantics matching those of Python's==. This is not supported right now for the following reasons:
- It was implemented in the MPL11, but it was not shown to be useful so far.
- It does not make sense for
not_equalto have an arity of more than 2, onlyequalcould maybe have those semantics, which would break symmetry.
|
constexpr |
#include <boost/hana/fwd/not_equal.hpp>
Returns a Logical representing whether x is not equal to y.
The not_equal function can be called in two different ways. First, it can be called like a normal function:
However, it may also be partially applied to an argument by using not_equal.to:
In other words, not_equal.to(x) is a function object that is equivalent to partial(not_equal, x). This is provided to enhance the readability of some constructs, especially when using higher order algorithms.
Given a Logical Bool and two Comparables A and B that share a common embedding, the signature is \( \mathtt{not\_equal} : A \times B \to Bool \).
| x,y | Two objects to compare for inequality. |