In a mathematical sense, the property whether, for any types T1
and T2
, the trait implementation From<T2> for T1
exists, i.e. whether the trait bound T1: From<T2>
is satisfied, or not, can be seen as a “(binary) relation”. In this interpretation, the relation (between types) that the trait From
gives rise to, is “reflexive” in the mathematical sense of the term. See also the Wikipedia pages I linked.
More commonly known examples for binary relations in mathematics are e.g. the < and ≤ relations. For any number n, the the statement “n ≤ n” is always true, e.g. 2≤2, 3≤3, etc… are all true, so “≤”, is a reflexive relation, too. On the other hand the same doesn’t hold true for the ”<” relation, where something like 2<2 is false. While for “<” this goes as far as that “n < n” is actually false for all numbers, in general, even a single such counter-example would be sufficient for a relation not to be considered reflexive.
For example the Add
trait in Rust, with its implementation in the standard library, also gives rise to a relation between types, much like From
, but this relation is not reflexive: While for certain types, T: Add<T>
is fulfilled, for example i32: Add<i32>
, and in fact the reflexive case is so common that Add
comes with a shorthand, where a trait bound Foo: Add
is short for Foo: Add<Foo>
, there do exist lots of types that don’t implement Add<…>
at all, and even ones that do, but not reflexively.
For example there is no implementation for char
, because you are not supposed to think of unicode scalar values as numbers, but more as characters, and those don’t do arithmetic. Or e.g. for Instant
, there is an implementation for Instant: Add<Duration>
, but not Instant: Add<Instant>
, because you can offset points in time by time durations, but there’s no sense in adding points in time to each other. (E.g. there’s no sense in defining weird things like adding the year 2023 to itself giving, say, the year 4046; since any choice of a “0” point is just arbitrary, and we don’t like results depending on such arbitrary choices.) Another example is String
and &str
which do implement String: Add<&str>
, but neither &str
nor String
has a reflexive implementation; this is mainly an arbitrary API choice in order to encourage the user to create unnecessary allocations. (Though also some people don’t like it at all that strings allow a +
operator in Rust.)