Generic "types" are not types. They are functions at the level of the type system. A declaration like Point2D<T>
produces a type-level function with one input type, T
, and an output type. When you apply it to, say, f64
, it produces the concrete type struct { x: f64, y: f64 }
.
Traits are implemented for types. Implementing a trait for a generic "type" can be considered syntactic sugar for creating many implementations for all concrete types produced by that type-level function. Of course, for the type-level function to be able to produce a concrete type, it needs another concrete type as its input to begin with. Just like a regular, value-level function needs an input value (argument) in order to produce an output (return) value.
Thus, when you impl Trait for Point2D<T>
, you have to pass a concrete type to the Point2D
type-level function. But if you want to implement the trait for all such cases, then of course you can't just pick one single type, and you can't possibly enumerate all types, either. (It would be majorly inconvenient at least, but also impossible when considering that downstream crates may create new T
s that you have never even dreamt of.) You basically want to express universal quantification instead: "for all concrete types T
, let Point2D<T>
have the following implementation". But notice that this in turn itself requires a free variable, T
, to quantify over. Basically, the impl
just passes through the requirement of a concrete type, much like value-level functions can call each other and require arguments to be passed through:
fn foo(x: u64) -> u64 {
x * 2
}
fn bar(x: u64) -> u64 {
foo(x) * 3
}
println!("{}", bar(4)); // prints 24
In the above example, I think we can agree you would be majorly upset if any and all occurrences of the letter x
would somehow magically refer to the same function argument, and thus bar
could call foo(x)
without ever declaring that it itself takes an argument named x
. Since a name like x
is used all over the place, having it be "inferred" magically would be disastrous with regards to code legibility and structure. It would basically amount to having implicit global variables everywhere and uncontrollably.
The same would happen if the <T>
free type variable weren't required in generic impls. It would basically be a global type variable. Given that <T>
is also used all over the place in generic code, having it inferred implicitly to something "obvious" would be highly ambiguous and have a far-reaching negative impact on code quality.