Implement From on a trait which has Self as member - rust

I want to be able to convert any iterator into MyType.
impl<T, I: IntoIterator<Item = T>> From<I> for MyType<T>
As in
MyType<T>::from<I: IntoIterator>(iter: I) -> MyType<T>
As one expects, it makes sense for MyType to itself be convertible to an Iterator and satisfy IntoIterator as a trait, and it does.
But From is automatically implemented reflexively for any type, any type can convert into itself of course, and this is where the compiler barks:
error[E0119]: conflicting implementations of trait
`std::convert::From<MyType<_>>` for type `MyType<_>`:
My generic implementation for all IntoIterators conflicts with the default one. If Rust did not provide a default one then it would actually work albeit being needlessly expensive.
Is there any way to implement the trait for any member of IntoIterator except MyType?

There is actually a precedent in the Rust standard library: Iterator::collect is about creating a new value from an iterator.
Following this model, rather than implementing std::convert::From, you should implement std::iter::FromIterator.
And then there will be no conflict.

Related

What are "Blanket Implementations" in Rust?

When looking through the documentation of Rust structs, I often come across a section with the title "Blanket Implementations". I have heard that it can be used to implement a trait for all types or all types that match some condition but I am not sure why this is needed.
So what really are Blanket Implementations and why are they useful in Rust?
A blanket implementation is an implementation of a trait on a generic parameter:
impl<T> Trait for T
They usually also have where clauses involved since it is very hard to do anything useful to an unconstrained T. This does not cover things like impl<T> Trait for Vec<T>, which is a generic implementation but not a blanket implementation.
They are documented separately since they are applied without any particularity and may or may not be relevant to the type you're looking at. Whereas for the normal "Trait Implementations" section, all those traits at least had some thought for the specific type in mind (usually).
They are patently useful since it implements the trait for anything, in the entire ecosystem! If something satisfies the constraints, then it is able to take advantage of the implementation without needing to implement it themselves. You do not need to do anything to "opt-in" besides bringing the trait into scope.
Some notable ones:
From<T> is implemented for all T (the identity implementation)
Into<U> is implemented for all T where T: From<U> (the reflexive implementation that allows you to call .into() when a matching From implementation exists)
Any is implemented for all T where T: 'static
They are also needed to implement "trait aliases" where you create a trait that is constrained over multiple other traits (handy for reducing boilerplate and needed for multi-trait trait objects). You use a blanket implementation that the trait is implemented for any type satisfying the super-traits:
trait MyCoolAsyncTrait: AsyncRead + AsyncWrite + AsyncSeek + 'static {}
impl<T> MyCoolAsyncTrait for T
where
T: AsyncRead + AsyncWrite + AsyncSeek + 'static
{ }
Be careful when adding them to your types though. Because of their extensive scope, they can easily conflict with other trait implementations that may be desirable. You can only define one blanket implementation per type (even if the constraints are non-overlapping).
See also:
What are blanket implementations? (Rust forum)
Traits: Defining Shared Behavior in the Rust book
Is there any way to create a type alias for multiple traits?
How is there a conflicting implementation of `From` when using a generic type?
Why do blanket implementations for two different traits conflict?

Rust constraints for generic types Item

While looking through the documentation for flatten.
pub struct Flatten<I>
where
I: Iterator,
<I as Iterator>::Item: IntoIterator,
I was wondering why this is needed -- the last line.
Would the following not be sufficient?
I::Item: IntoIterator,
After all I is constrained to be Iterator on the line before.
This is not necessary, indeed, and the actual code uses completely another form (an unstable Trait<Assoc: Trait> syntax, similar to the equality syntax Trait<Assoc = Type>). It is just rustdoc showing that, because in theory you could have a type parameter implementing two traits that both have the same associated item.

Why is std::borrow::Borrow not implementet for every Type?

On the documentation it is stated that
impl<T> Borrow<T> for T where
T: ?Sized,
I would read this:
This Trait is implemented for every Type, even unsized ones.
Is this correct?
I got the error message:
the trait std::borrow::Borrow<T> is not implemented for &num_complex::Complex<f64>
which I can't make sense of.
(I do not want to post the whole code, I just want some clarification about which types implement std::borror::Borrow)
The important thing to recognize is that in the blanket impl there is only one T and it has to represent the same type in both places:
impl<T> Borrow<T> for T
where T: ?Sized
implements for each type T, only the specific trait Borrow<T>. i64 implements Borrow<i64>, String implements Borrow<String>, etc. When we instantiate this with T = &num_complex::Complex<f64>, what trait is implemented?
impl Borrow<&num_complex::Complex<f64>> for &num_complex::Complex<f64> // (not compilable code, just illustrative)
In words, you can borrow a &Complex<f64> as a &Complex<f64>, but you can't borrow it as any arbitrary T (which wouldn't make much sense, anyway).
You're using this in some generic code where T can be anything, so the blanket impl of Borrow<T> for T doesn't apply. You can probably fix this by adding a trait bound:
where num_complex::Complex<f64>: Borrow<T>
which means that Complex<f64> itself implements Borrow<T>, or
where for<'a> &'a num_complex::Complex<f64>: Borrow<T>
which means that any reference to Complex<f64> implements Borrow<T>. Depending on your actual code either or both of these may work due to autoref/autoderef.

Why can a function on a trait object not be called when bounded with `Self: Sized`?

I have the following code:
trait Bar {
fn baz(&self, arg: impl AsRef<str>)
where
Self: Sized;
}
struct Foo;
impl Bar for Foo {
fn baz(&self, arg: impl AsRef<str>) {}
}
fn main() {
let boxed: Box<dyn Bar> = Box::new(Foo);
boxed.baz();
}
playground
Which results in this error:
error: the `baz` method cannot be invoked on a trait object
--> src/main.rs:15:11
|
15 | boxed.baz();
| ^^^
Why is this not possible? It works when I remove the Self: Sized bound, but then I can't use generics which make the function more comfortable for the caller.
This is not a duplicate of Why does a generic method inside a trait require trait object to be sized? which asks why you can't call baz from a trait object. I'm not asking why the bound is required; this has already been discussed.
Because Rust's generics system works through monomorphization.
In Java, for example, type parameters in a generic function turn into variables of type Object, and are casted as necessary. Generics in languages like this simply serves as a tool to help verify the correctness of types within code.
Languages such as Rust and C++ use monomorphization for generics. For each combination of type parameters a generic function is invoked with, specialized machine code is generated which runs that function with those combinations of type parameters. The function is monomorphized. This allows data to be stored in place, eliminates the cost of casting, and allows the generic code to call "static" functions on that type paramameter.
So why can't you do that on a trait object?
Trait objects in many languages, including Rust, are implemented using a vtable. When you have some type of pointer to a trait object (raw, reference, Box, reference counter, etc.), it contains two pointers: the pointer to the data, and a pointer to a vtable entry. The vtable entry is a collection of function pointers, stored in an immutable memory region, which point to the implementation of that trait's methods. Thus, when you call a method on a trait object, it looks up the function pointer of the implementation in the vtable, and then makes an indirect jump to that pointer.
Unfortunately, the Rust compiler cannot monomorphize functions, if it does not know at compile time the code that implements the function, which is the case when you call a method on a trait object. For that reason, you cannot call a generic function (well, generic over types) on a trait object.
-Edit-
It sounds like you're asking why the : Sized restriction is necessary.
: Sized makes it so that the trait cannot be used as a trait object. I suppose there could be a couple of alternatives. Rust could implicitly make any trait with generic functions not object safe. Rust could also implicitly prevent generic functions from being called on trait objects.
However, Rust tries to be explicit with what the compiler is doing, which these implicit approaches would go against. Wouldn't it be confusing, anyways, for a beginner to try and call a generic function on a trait object and have it fail to compile?
Instead, Rust lets you explicitly make the entire trait not object safe
trait Foo: Sized {
Or explicitly make certain functions only available with static dispatch
fn foo<T>() where Self: Sized {
The bound makes the method not object safe. Traits that are not object safe cannot be used as types.
Methods that take Self as an argument, return Self or otherwise require Self: Sized are not Object safe. That's because methods on a trait object are called via dynamic dispatch and the size of the trait implementation cannot be known at compile time. -- Peter Hall
Citing the official docs:
Only traits that are object-safe can be made into trait objects. A trait is object-safe if both of these are true:
the trait does not require that Self: Sized
all of its methods are object-safe
So what makes a method object-safe? Each method must require that Self: Sized or all of the following:
must not have any type parameters
must not use Self
See also:
this answer from Why does a generic method inside a trait require trait object to be sized?

Why does T not implement AsRef<T>?

This code does not compile:
fn ref_on_int<T>(_: T) where T: AsRef<i32> {}
fn main() {
ref_on_int(&0_i32)
}
because
the trait bound `i32: std::convert::AsRef<i32>` is not satisfied
Why is it so?
This could be useful for example with a newtype like
struct MyInt(i32);
impl AsRef<i32> for MyInt {
/* etc. */
}
then you could indifferently pass a reference on an i32 or a reference on a MyInt, because in the memory we have in both cases an i32.
AsRef and Borrow are pretty similar at first glance, but they are used for different things. The Book describes the difference between them pretty well:
Choose Borrow when you want to abstract over different kinds of
borrowing, or when you’re building a data structure that treats owned
and borrowed values in equivalent ways, such as hashing and
comparison.
Choose AsRef when you want to convert something to a reference
directly, and you’re writing generic code.
In your case Borrow is a more reasonable choice because there is no conversion involved.
As for the question of why AsRef is not implemented between different integral types, I guess this would go against the intent of Rust to be expressive about casts; I think it's similar to the question Why can't I compare two integers of different types?.
Here's an authoritative answer by Aaron Turon:
Borrow provides a blanket implementation T: Borrow<T>, which is essential for making the above collections work well. AsRef provides a different blanket implementation, basically &T: AsRef<U> whenever T: AsRef<U>, which is important for APIs like fs::open that can use a simpler and more flexible signature as a result. You can't have both blanket implementations due to coherence, so each trait is making the choice that's appropriate for its use case.
I think that is one of the differences of AsRef and Borrow.
That is, Borrow<T> is implemented directly for &T, while AsRef<T> is not implemented for &T.
Funny thing is that AsRef<U> is implemented for &T if T implements AsRef<U>. That is, if you can use AsRef with a type, you can use it with a reference to the same time.
And another funny thing is that Borrow<T> is implemented for &T but also for T!

Resources