Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I implement trait B for all types that implement trait A if both traits are implemented for references?

Tags:

rust

We have two traits A and B for which

  1. I can trivially implement B for all types that implement A.
  2. I can trivially implement A for references to any type implementing A.
  3. I can trivially implement B for references to any type implementing B.

Actually doing all three leads to a conflict, because now references to types that implement A would have two implementations of B for them. One due to the impl<T: A> A for &T and one transitively due to the impl<T: A> B for T (and then the impl<T: B> B for &T.

I can't remove the impl<T: B> B for &T, because there might be types that implement B but not A

Here's an example code exhibiting the behaviour.

trait A {}
trait B {}

impl<'a, T: A> A for &'a T {}
impl<T: A> B for T {}

impl<'a, T: B> B for &'a T {}

which results in the following error:

error[E0119]: conflicting implementations of trait `B` for type `&_`:
  |
  | impl<T: A> B for T {}
  | --------------------- first implementation here
  | impl<'a, T: B> B for &'a T {}
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_`

Is it possible to use the Rust typesystem in a way to ensure that when there is an impl B for &A, we don't create one for &B?

like image 690
oli_obk Avatar asked Nov 22 '16 13:11

oli_obk


People also ask

How do you implement traits?

Implementing a trait on a type is similar to implementing regular methods. The difference is that after impl , we put the trait name we want to implement, then use the for keyword, and then specify the name of the type we want to implement the trait for.

What are implementations in Rust?

An implementation is an item that associates items with an implementing type. Implementations are defined with the keyword impl and contain functions that belong to an instance of the type that is being implemented or to the type statically. There are two types of implementations: inherent implementations.

What is a blanket implementation?

What are blanket implementations? Blanket implementations leverage Rust's ability to use generic parameters. They can be used to define shared behavior using traits. This is a great way to remove redundancy in code by reducing the need to repeat the code for different types with similar functionality.

What is the point of traits in Rust?

A trait tells the Rust compiler about functionality a particular type has and can share with other types. Traits are an abstract definition of shared behavior amongst different types. So, we can say that traits are to Rust what interfaces are to Java or abstract classes are to C++.


1 Answers

There has been some discussion on the Rust internals forum on this topic, starting with a blog post by Nicholas Matsakis about how to handle the issue of overlapping trait implementations.

Today, (unstable) Rust has some impl specialisation, but that only works for strictly more specific impls of a more generic one.

So I think the answer is that there isn't a good way to do it today, but at some point in the future there's a good chance that Rust will evolve to allow expressing overlapping trait impls.

like image 119
Chris Emerson Avatar answered Sep 23 '22 19:09

Chris Emerson