While playing around with Rust and its generics I came along some problem for which I cannot find any documentation.
I have implemented a type Wrapper which wraps another type. At some point I wanted to implement the From trait.
impl<TSrc, TDst> From<Wrapper<TSrc>> for Wrapper<TDst>
where
TSrc: From<TDst>
{
fn from(other: Wrapper<TSrc>) -> Self {
todo!()
}
}
rustc complains with following error
58 | impl<TSrc, TDst> From<Wrapper<TSrc>> for Wrapper<TDst>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<T> From<T> for T;
This makes sense if TSrc and TDst are the same. Is it somehow possible to explicitly exclude TSrc from TDst?
No, it is not possible to exclude specific types in a generic implementation.
There's not really a general workaround beyond "do something else" which would typically look like an inherent conversion method, using a different (custom) trait, or allowing another mechanism for users to access the inner values and do the conversion themselves.
There may be mechanisms in the future like specialization or negative impls that could allow such an implementation (or similar), but nothing is on the horizon.
See also:
How is there a conflicting implementation of `From` when using a generic type?
Why do blanket implementations for two different traits conflict?
Is it possible to exclude a type from generic trait implementation?
I would like to have all float comparisons done with float_cmp::approx_eq (for example), but keep using the equality comparison operator == for it. How do I achieve this?
impl PartialEq for f32 {
fn eq(&self, other: &Self) -> bool {
approx_eq!(f32, *self, *other)
}
}
Results in:
error[E0119]: conflicting implementations of trait `std::cmp::PartialEq` for type `f32`
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
This is not possible:
This trait implementation is in direct conflict with an existing implementation. There is no trait overriding mechanism. In the future you may be able to specialize a generic trait implementation, but this wouldn't be covered by that anyway.
Rust has "orphan rules" that govern what trait implementations you are allowed to define. In short, some part of the trait or type must be defined by the current crate. Neither PartialEq and f32 are defined by you, so you cannot create this implementation.
The approx_eq! macro from float_cmp expands to code that uses == internally, so such implementation if it were allowed would cause infinite recursion.
I don't think there is a way to accomplish this and I'm not sure I'd suggest using it even if there were. This would affect all cases where float comparison is done, even deep in your dependencies that could end up causing problems. And this leaves little option to do non-approximate equality even if you explicitly wanted to.
You should handle cases where you only want to consider approximate equality explicitly.
This question already has answers here:
Is there any way to restrict a generic type to one of several types?
(2 answers)
Closed 3 years ago.
We can restrict a type to one or more traits by where clause.
My questions are:
Is it possible to restrict a type to just primitive number types?
How?
No.
To use a parametric type, you need the trait to define the valid operations you want to call on it. So you need a trait (or more) with all the operations you want to call.
The “primitive” types in Rust are not special in any way. They define their operators via the traits from std::ops (though obviously using compiler intrinsics) just like any “non-primitive” numberic types.
In fact, the boundary between “primitive” and “non-primitive” numeric types is even somewhat blurred, since for targets that lack an FPU, the standard library may be implementing floating point types in code, and in Rust it can do it transparently to the user.
So really, there is no such thing as primitive number types. Number types are defined by providing whatever operators you need to call. So just restrict your type by the std::ops traits.
Since primitives are not trait types you cannot use as boundary to restrict a generic type. But you can directly implement for a specific type:
struct Struct<T>(T);
trait Printer {
fn print(&self);
}
impl Printer for Struct<i32> {
fn print(&self) {
println!("Printing for i32 value: {}", self.0);
}
}
fn main() {
let x = Struct(15_i32);
let _z = Struct(14.2_f64);
x.print();
//_z.print();//compile error
}
Playground
Alternatively you can use Borrow<S> trait as trick, you can restrict your generic parameter as like below : ( T: Borrow<S> means T can be borrowed as S ) .
impl<T> Printer for Struct<T>
where
T: Borrow<f64> + Debug,
{
fn print(&self) {
println!("Printing for f64 value: {:?}", self.0);
}
}
Playground
But since you can implement Borrow<f64> for any type, this kind of restriction may not be considered as strict.
Also just for the numeric primitives you can use traits from num-traits crate like ToPrimitive AsPrimitive
If you think about traits as compile time duck typing, then a better question would be: what are the exact traits you are looking for in a number? Most of the operations on them could be defined as trait constraints on your types, see: the standard operator traits.
Even if you would define a trait in an external crate and implement the behaviour for specific types only in that external crate, thinking that the trait implementation rules will help you there (i.e. a trait can only be implemented to a type if either the trait or the type or both are in your current crate) would still not limit anyone to implement your trait for their own types.
Therefore, I see no other option but to implement the behaviours without generics for each primitive number type. To avoid code duplication, I would probably use macros for this -- after all, if you think about it in some ways you would manually do what the compiler does while it monomorphises your generic code.
That being said I see no reason to limit behaviours to numbers but to certain traits and I would rely on them as I described it in the first paragraph.
The following code uses a struct with generic type. While its implementation is only valid for the given trait bound, the struct can be defined with or without the same bound. The struct's fields are private so no other code could create an instance anyway.
trait Trait {
fn foo(&self);
}
struct Object<T: Trait> {
value: T,
}
impl<T: Trait> Object<T> {
fn bar(object: Object<T>) {
object.value.foo();
}
}
Should the trait bound for the structure should be omitted to conform to the DRY principle, or should it be given to clarify the dependency? Or are there circumstances one solution should be preferred over the other?
I believe that the existing answers are misleading. In most cases, you should not put a bound on a struct unless the struct literally will not compile without it.
tl;dr
Bounds on structs express the wrong thing for most people. They are infectious, redundant, sometimes nearsighted, and often confusing. Even when a bound feels right, you should usually leave it off until it's proven necessary.
(In this answer, anything I say about structs applies equally to enums.)
0. Bounds on structs have to be repeated everywhere the struct is
This is the most obvious, but (to me) least compelling reason to avoid writing bounds on structs. As of this writing (Rust 1.65), you have to repeat every struct's bounds on every impl that touches it, which is a good enough reason not to put bounds on structs for now. However, there is an accepted RFC (implied_bounds) which, when implemented and stabilized, will change this by inferring the redundant bounds. But even then, bounds on structs are still usually wrong:
1. Bounds on structs leak out of abstractions.
Your data structure is special. "Object<T> only makes sense if T is Trait," you say. And perhaps you are right. But the decision affects not just Object, but any other data structure that contains an Object<T>, even if it does not always contain an Object<T>. Consider a programmer who wants to wrap your Object in an enum:
enum MyThing<T> { // error[E0277]: the trait bound `T: Trait` is not satisfied
Wrapped(your::Object<T>),
Plain(T),
}
Within the downstream code this makes sense because MyThing::Wrapped is only used with Ts that do implement Thing, while Plain can be used with any type. But if your::Object<T> has a bound on T, this enum can't be compiled without that same bound, even if there are lots of uses for a Plain(T) that don't require such a bound. Not only does this not work, but even if adding the bound doesn't make it entirely useless, it also exposes the bound in the public API of any struct that happens to use MyThing.
Bounds on structs limit what other people can do with them. Bounds on code (impls and functions) do too, of course, but those constraints are (presumably) required by your own code, while bounds on structs are a preemptive strike against anyone downstream who might use your struct in an innovative way. This may be useful, but unnecessary bounds are particularly annoying for innovators because they constrain what can compile without usefully constraining what can actually run (more on that in a moment).
2. Bounds on structs are redundant with bounds on code.
So you don't think downstream innovation is possible? That doesn't mean the struct itself needs a bound. To make it impossible to construct an Object<T> without T: Trait, it is enough to put that bound on the impl that contains Object's constructor(s); if it's impossible to call a_method on an Object<T> without T: Trait you can say that on the impl that contains a_method, or perhaps on a_method itself. (Until implied_bounds is implemented, you have to, anyway, so you don't even have the weak justification of "saving keystrokes.")
Even and especially when you can't think of any way for downstream to use an un-bounded Object<T>, you should not forbid it a priori, because...
3. Bounds on structs mean something different to the type system than bounds on code.
A T: Trait bound on Object<T> means more than "all Object<T>s have to have T: Trait"; it actually means something like "the concept of Object<T> itself does not make sense unless T: Trait", which is a more abstract idea. Think about natural language: I've never seen a purple elephant, but I can easily name the concept of "purple elephant" despite the fact that it corresponds to no real-world animal. Types are a kind of language and it can make sense to refer to the idea of Elephant<Purple>, even when you don't know how to create one and you certainly have no use for one. Similarly, it can make sense to express the type Object<NotTrait> in the abstract even if you don't and can't have one in hand right now. Especially when NotTrait is a type parameter, which may not be known in this context to implement Trait but in some other context does.
Case study: Cell<T>
For one example of a struct that originally had a trait bound which was eventually removed, look no farther than Cell<T>, which originally had a T: Copy bound. In the RFC to remove the bound many people initially made the same kinds of arguments you may be thinking of right now, but the eventual consensus was that "Cell requires Copy" was always the wrong way to think about Cell. The RFC was merged, paving the way for innovations like Cell::as_slice_of_cells, which lets you do things you couldn't before in safe code, including temporarily opt-in to shared mutation. The point is that T: Copy was never a useful bound on Cell<T>, and it would have done no harm (and possibly some good) to leave it off from the beginning.
This kind of abstract constraint can be hard to wrap one's head around, which is probably one reason why it's so often misused. Which relates to my last point:
4. Unnecessary bounds invite unnecessary parameters (which are worse).
This does not apply to all cases of bounds on structs, but it is a common point of confusion. You may, for instance, have a struct with a type parameter that should implement a generic trait, but not know what parameter(s) the trait should take. In such cases it is tempting to use PhantomData to add a type parameter to the main struct, but this is usually a mistake, not least because PhantomData is hard to use correctly. Here are some examples of unnecessary parameters added because of unnecessary bounds: 1 2 3 4 5 In the majority of such cases, the correct solution is simply to remove the bound.
Exceptions to the rule
Okay, when do you need a bound on a struct? I can think of two possible reasons.
In Shepmaster's answer, the struct will simply not compile without a bound, because the Iterator implementation for I actually defines what the struct contains. One other way that a struct won't compile without a bound is when its implementation of Drop has to use the trait somehow. Drop can't have bounds that aren't on the struct, for soundness reasons, so you have to write them on the struct as well.
When you're writing unsafe code and you want it to rely on a bound (T: Send, for example), you might need to put that bound on the struct. unsafe code is special because it can rely on invariants that are guaranteed by non-unsafe code, so just putting the bound on the impl that contains the unsafe is not necessarily enough.
But in all other cases, unless you really know what you're doing, you should avoid bounds on structs entirely.
Trait bounds that apply to every instance of the struct should be applied to the struct:
struct IteratorThing<I>
where
I: Iterator,
{
a: I,
b: Option<I::Item>,
}
Trait bounds that only apply to certain instances should only be applied to the impl block they pertain to:
struct Pair<T> {
a: T,
b: T,
}
impl<T> Pair<T>
where
T: std::ops::Add<T, Output = T>,
{
fn sum(self) -> T {
self.a + self.b
}
}
impl<T> Pair<T>
where
T: std::ops::Mul<T, Output = T>,
{
fn product(self) -> T {
self.a * self.b
}
}
to conform to the DRY principle
The redundancy will be removed by RFC 2089:
Eliminate the need for “redundant” bounds on functions and impls where
those bounds can be inferred from the input types and other trait
bounds. For example, in this simple program, the impl would no longer
require a bound, because it can be inferred from the Foo<T> type:
struct Foo<T: Debug> { .. }
impl<T: Debug> Foo<T> {
// ^^^^^ this bound is redundant
...
}
It really depends on what the type is for. If it is only intended to hold values which implement the trait, then yes, it should have the trait bound e.g.
trait Child {
fn name(&self);
}
struct School<T: Child> {
pupil: T,
}
impl<T: Child> School<T> {
fn role_call(&self) -> bool {
// check everyone is here
}
}
In this example, only children are allowed in the school so we have the bound on the struct.
If the struct is intended to hold any value but you want to offer extra behaviour when the trait is implemented, then no, the bound shouldn't be on the struct e.g.
trait GoldCustomer {
fn get_store_points(&self) -> i32;
}
struct Store<T> {
customer: T,
}
impl<T: GoldCustomer> Store {
fn choose_reward(customer: T) {
// Do something with the store points
}
}
In this example, not all customers are gold customers and it doesn't make sense to have the bound on the struct.
Is there an easy way to annotate fields in a struct so that they are ignored when deriving the PartialEq trait? For example:
#[derive(PartialEq,Eq)]
pub struct UndirectedGraph {
nodes: HashMap<NodeIdx, UndirectedNode>,
// mapping of degree to nodes of that degree
degree_index: Vec<HashSet<NodeIdx>>,
}
I want two undirected graphs to be considered equal when they have the same nodes field, but the degree_index field may differ (the vector may contain extra empty hash-sets at the end).
Obviously I could just implement the trait manually, but automatic derivation would be simpler.
Check out the derivative create (docs). It provides alternate derive macros with more power than the standard library versions, including ways to ignore fields for Hash and PartialEq traits.
No, there is no way to do that currently and I doubt it will be supported.
You could consider making the fields that you want to compare into a sub-struct which is derived, which would make the implementation for the larger struct trivial.
I would also recommend the derivative crate if you need a more sophisticated form of #[derive].
If you only need something like this once or twice, it may be easier to just implement the required traits manually rather than derive them. PartialEq and Eq are very easy to implement yourself:
impl PartialEq for UndirectedGraph {
fn eq(&self, other: &Self) -> bool {
self.nodes == other.nodes
}
}
impl Eq for UndirectedGraph {}