I'm working on building a more fluid intuition for how to write more generic code in Rust And, getting a better feel for when to specify my own traits. For now, I'm limiting the scope to "generic over the type" not lifetimes, nor constants.
Traits - where I am
I first equated them to "type classes" in Haskell. Both type classes and traits have been explained with the idea of "an interface". As a way to express type bounds, type classes and traits relate to each other very well. Ad hoc polymorphism is also used to describe a "across" types capability. While I have seen credible sources describe traits "as types in Rust", it is more true with trait objects, and thus does introduce an ad hoc polymorphism.
However, traits are far more a "go to" in Rust, than type classes are in Haskell (type classes in general should be used for "canonical" properties shared across types, e.g., types that "commute", are "functors" etc.). Similarly, what I know about interfaces is incomplete for what traits do in Rust.
Concrete traits, concrete types, got it
I have put the idea of generic code with traits likely to go beyond the idea of the "base case" of using a concrete trait to augment my types with additional functionality. In concrete types and traits, it's straightforward enough.
Generic Types
The generic version of a type is also pretty clear in my mind: Option
, Vec
and the like are type constructors Vec: Type -> Type
. I only use this terminology because it taps into a solid amount of FP concepts such as Functors, Monoids and the like. This level setting, is likely a boundary where a "trait"'s ability to augment my type's functionality likely stops. Specifically, a generic trait cannot make my concrete type a type constructor... or can it, just in a weird sort of way (Hash
trait + concrete type)?
Generic traits
When I consider a generic trait, it gets fuzzy. So far, my model specifies how the type parameter can relate to self
, the type that implements the trait and similarly how the two type parameters can relate when the type is also generic.
where I have GenericTrait<U>
and GenericSruct<T>
-
"pass-through": T = U. Here the trait enhances whatever
MyStruct
inMyStruc<T>
specifies (in other words, does not know of, nor can interact withT
- this only works if I also consider traits with associated types as generic despite not having a type parameter. E.g.,
Vec<T>
implementsIntoIterator
(generic by way of associated types)- here one specifies the other; 1:1
?? Is it possible to generically specify use of a concrete trait on a generic type??
- this only works if I also consider traits with associated types as generic despite not having a type parameter. E.g.,
-
is orthogonal to
self
: T != U and remains unaware of T (i.e., U cannot depend on bounds put on T) e.g., the[Hash]
(Hash in std::hash - Rust) and[Index]
(Index in std::ops - Rust) traits.- augment my type with a hash capability that can use whatever hash function "works best"
?? Is it possible to make a generic trait concrete by implementing a new trait, e.g., Trait Hash -> Trait HashWithThisHasher (so able to do so without implementing the trait for a given type).
-
interaction between T and U where U might depend on the traits implemented by T?
All in all, another way of expressing what I'm after here, is that in one extreme approach I could express my computation logic using nothing but traits + dummy struct. The only clear benefit of a struct is the ability to store data. Can all my methods be coded using traits? Where would this approach fall flat?