What does "reflexive trait" mean?

I found the following sentence in the documentation of From.

From is reflexive, which means that From for T is implemented

I would like to know what kind of trait can be considered "reflexive".

which means that From for T is implemented

What if it is for &T instead of for T?
What if it has a where clause?

Assume you have the following trait.

pub trait MyTrait {}

In which of the following cases would you say "MyTrait is reflexive"?

  1. MyTrait implemented only for T
impl<T> MyTrait for T
  1. MyTrait implemented only for T with a where clause
impl<T> MyTrait for T where T: Display
  1. MyTrait implemented only for &T
impl<T> MyTrait for &T
  1. MyTrait implemented only for &T with a where clause
impl<T> MyTrait for &T where T: Display

From<T> for T is reflexive because it allows you to convert a type into itself. There isn't really a general Rust concept of a "reflexive trait", it's a property of the operation the trait is modelling more than anything else.

3 Likes

Understood. Thank you so much :smiley:

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.)

4 Likes

Wow, It seems I have a lot to learn.
Thank you so much for the information :+1:

The mathematical side notes are of course somewhat unrelated to programming or learning Rust, but yes, mathematics can indeed be a surprisingly large fields, and much even of the most basic fundamentals (sets and relations being a good example) of “mathematics” – as a science (or a university subject) – never sees the light of day in school education. (Though school mathematics is not only focusing on a different/narrower selection of topics, but also sometimes criticized its approach to the subject.)

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.