I am looking for the answer why a sized trait is not object safe, for example:
trait Foo:Sized{}
Foo is not object safe.
I have read some posts about object safey, like object-safety and sizedness-in-rust. I find the deep reason is compiler automatically impl Foo for Foo.
I confuse why compiler do this and why this cause Foo not object safe?
Thank you very much.
impl Foo for Foo is the way to write in Rust "implement trait Foo for trait object Foo". A trait can be only object-safe if the trait object for this trait implements the trait. Obviously, there is no much sense having a trait object, that does not implement itself.
By specifying trait Foo : Sized {}, you require that all implementors of Foo must also implement Sized. But all trait objects in Rust are ?Sized, meaning they can be unsized. Thus the trait object for type Foo : Sized cannot implement Foo, so you cannot write
impl Foo for Foo
or, in other words, the trait is not object safe.
Related
What is the difference between filter(|x| func(x)) and filter(func)? Perhaps a good place to start would be to understand how filter(func) could be written using syntax akin to filter(|x| func(x)). My code looks like this:
fn filter_out_duplicates(vec_of_vecs: Vec<Vec<u8>>) -> Vec<Vec<u8>> {
vec_of_vecs
.into_iter()
.filter(all_unique)
.collect()
}
pub fn all_unique<T>(iterable: T) -> bool
where
T: IntoIterator,
T::Item: Eq + Hash,
{
let mut unique = HashSet::new();
iterable.into_iter().all(|x| unique.insert(x))
}
error[E0599]: the method `collect` exists for struct `Filter<std::vec::IntoIter<Vec<u8>>, fn(&Vec<u8>) -> bool {tmp::all_unique::<&Vec<u8>>}>`, but its trait bounds were not satisfied
--> src/main.rs:44:56
|
44 | vec_of_vecs.into_iter().filter(all_unique).collect()
| ^^^^^^^ method cannot be called on `Filter<std::vec::IntoIter<Vec<u8>>, fn(&Vec<u8>) -> bool {tmp::all_unique::<&Vec<u8>>}>` due to unsatisfied trait bounds
|
::: /.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/adapters/filter.rs:15:1
|
15 | pub struct Filter<I, P> {
| ----------------------- doesn't satisfy `_: Iterator`
|
= note: the following trait bounds were not satisfied:
`<fn(&Vec<u8>) -> bool {tmp::all_unique::<&Vec<u8>>} as FnOnce<(&Vec<u8>,)>>::Output = bool`
which is required by `Filter<std::vec::IntoIter<Vec<u8>>, fn(&Vec<u8>) -> bool {tmp::all_unique::<&Vec<u8>>}>: Iterator`
`fn(&Vec<u8>) -> bool {tmp::all_unique::<&Vec<u8>>}: FnMut<(&Vec<u8>,)>`
which is required by `Filter<std::vec::IntoIter<Vec<u8>>, fn(&Vec<u8>) -> bool {tmp::all_unique::<&Vec<u8>>}>: Iterator`
`Filter<std::vec::IntoIter<Vec<u8>>, fn(&Vec<u8>) -> bool {tmp::all_unique::<&Vec<u8>>}>: Iterator`
which is required by `&mut Filter<std::vec::IntoIter<Vec<u8>>, fn(&Vec<u8>) -> bool {tmp::all_unique::<&Vec<u8>>}>: Iterator`
which is required by `&mut Filter<std::vec::IntoIter<Vec<Placement>>, fn(&Vec<Placement>) -> bool {all_unique::<&Vec<Placement>>}>: Iterator`
But the code compiles if I use |x| all_unique(x). I know deciphering compiler errors is the recommended way of solving problems in Rust but I find this error pretty impenetrable.
I found a discussion that seemed to commiserate about the error more than explain coercions but I found the chapter on coercions in the Rustonomicon too short to provide understanding.
This case is not related to coercions. This is another case of late-bound vs. early-bound lifetimes.
Rust has two kinds of lifetimes: early-bound and late-bound. The difference boils down to it is decided what lifetime to use.
For late bound lifetimes, you get a Higher-Ranked Trait Bound - something like for<'a> fn(&'a i32). Then, a lifetime is picked only when the function is called.
For early-bound lifetimes, on the other hand, you get fn(&'some_concrete_lifetime i32). The lifetime may be inferred, sometimes omitted, but it's there. And it has to be decided at the time we decide the type for the function pointer/item.
filter() expects a HRTB function, that is, with a late bound lifetime. This is because the desugaring for FnMut(&Self::Item) -> bool, which is the bound in filter(), is for<'a> FnMut(&'a Self::Item) -> bool, or, if you wish, for<'a> FnMut<(&'a Self::Item,), Output = bool>.
Your all_unique(), however, is generic over T: IntoIterator. And if we set T = &'a Vec<u8>, then 'a is early bound. This is because lifetimes from generic parameters are always early bound - essentially, because we can't late-bind generic arguments, as there is no way in Rust to express for<T>, as generic type parameters are monomorphized and so this is generally impossible.
So, if we reveal the elided lifetimes, you want to satisfy the trait bound fn(&'some_lifetime Vec<u8>) -> bool: for<'all_lifetimes> FnMut(&'all_lifetimes Vec<u8>) -> bool, and this bound is false. This is the reason for the error you saw.
If we use a closure, however, we generate a closure that is specific for the type &'lifetime Vec<u8>. Since it is not generic over the type, the lifetime can be late bound.
I'm not 100% sure about what it is happening here. It could even be considered a compiler limitation/bug, depending on your point of view, but I think that this is what happens:
When you write filter(all_unique), being all_unique a generic function, it is resolved as taking a reference to the item it is iterating upon, as per the definition of filter:
fn filter<P>(self, predicate: P) -> Filter<Self, P>ⓘ where
P: FnMut(&Self::Item) -> bool,
So you are actually calling all_unique<&Vec<u8>>. You may think that all is ok, because that &Vec<u8> actually implements IntoIterator and the other constraints.
But the issue is with lifetimes. See, when in filter there is the constraint P: FnMut(&Self::Item) -> bool that is actually syntactic sugar for P: for <'a> FnMut(&'a Self::Item) -> bool, that is the function must be able to accept any lifetime, and your function cannot.
But, wait! you may say that your function all_unique<T> certainly can take T: 'a for any lifetime 'a. And that is true, but that is not what is happening here: you are calling filter<P> with P=all_unique::<&'f Vec<u8>> being 'f that particular lifetime. And that lifetime is not any lifetime! Now your all_unique function is tainted with a particular lifetime and it does not satisfy the for <'a> ... thing above.
Surely, you do not actually need that for <a>` here because you are calling the function with the proper lifetime, but the syntax is what it is and it forces the error.
The obvious solution is to write all_unique to take a reference:
pub fn all_unique<T>(iterable: &T) -> bool
That is actually sintactic sugar for:
pub fn all_unique<'a, T>(iterable: &'a T) -> bool
where the universality of 'a (that for <'a> thing) is implicit.
And now calling filter(all_unique) selects the generic all_unique::<Vec<u8>>, that is untainted with lifetimes and can be called with any 'a.
And this is indeed is a syntactic limitation, you can just write:
pub fn all_unique<T> (iterable: T) -> bool { /* ... */ }
pub fn all_unique_ref<'a, T> (iterable: &'a T) -> bool {
all_unique::<&T>(iterable)
}
And writing filter(all_unique_ref) will work while filter(all_unique) will not.
Your solution of using a lambda expression:
filter(|x| all_unique(x))
is just like that all_unique_ref but anonymous.
TL;DR; The original error is caused because the lifetime of the argument is captured in the type of the generic function instead of in the usage of that function. And that makes filter() unhappy because its argument does not look generic enough.
The following code compiles fine:
struct StructA<F>(F);
impl<F, T> StructA<F> where F: Fn() -> T {}
Although T doesn't show up in StructA's type parameters, it is still constrained due to the where clause. This trick is used, for example, in std::iter::Map so Map<I, F> only needs two type parameters while the impl<B, I, F> Iterator for Map<I, F> takes three.
However the following code does not compile:
struct StructB<F>(F);
impl<F, T> StructB<F> where F: Fn(T) -> T {}
error[E0207]: the type parameter `B` is not constrained by the impl trait, self type, or predicates
--> src/lib.rs:5:9
|
5 | impl<F, T> StructB<F> where F: Fn(T) -> T {}
| ^ unconstrained type parameter
For more information about this error, try `rustc --explain E0207`.
error: could not compile `playground` due to previous error
Playground Link
This is unintuitive, why would using T in more places make it less constrained? Is this intended or is it a limitation in Rust?
Note this also happens with regular traits, i.e. the desugared version of Fn:
trait FnTrait<Args> {
type Output;
}
// Works
struct StructA<F>(F);
impl<F, T> StructA<F> where F: FnTrait<(), Output = T> {}
// Fails
struct StructB<F>(F);
impl<F, T> StructB<F> where F: FnTrait<(T,), Output = T> {}
Playground Link
Consider if we implement Fn manually (of course this requires nightly)...
#![feature(fn_traits, unboxed_closures)]
struct MyFunction;
impl<T> FnOnce<(T,)> for MyFunction {
type Output = T;
extern "rust-call" fn call_once(self, (v,): (T,)) -> T { v }
}
Now imagine your struct:
struct StructA<F>(F);
impl<F: FnOnce(T) -> T, T> StructA<F>{
fn foo(self) -> T { (self.0)() }
}
let s: StructA<MyFunction> = ...;
s.foo(); // What is `T`?
While the reference says:
Generic parameters constrain an implementation if the parameter appears at least once in one of:
...
As an associated type in the bounds of a type that contains another parameter that constrains the implementation
This is inaccurate. Citing the RFC:
Type parameters are legal if they are "constrained" according to the following inference rules:
...
If <T0 as Trait<T1...Tn>>::U == V appears in the impl predicates, and T0...Tn are constrained and T0 as Trait<T1...Tn> is not the impl trait reference then V is constrained.
That is, all type parameters should that appear in the trait should be constrained, not just one of them.
I've opened an issue in the reference repo.
Related: https://github.com/rust-lang/rust/issues/25041.
You always need to be able to deduce the generic type parameters of an impl from the self type of the impl (and possibly the trait being implemented, if it's a trait impl). In the first case, F: Fn() -> T, it is possible to derive T from the self type StructA<F>. However, with the trait bound F: Fn(T) -> T, this is not possible.
The difference between the two cases results from the fact that the return type of the closure trait Fn is an associated type, while the argument types are generic parameters. In other words, you can only implement Fn() -> T for any type F once, and that implementation will have a fixed return type T. The trait Fn(T) -> T, on the other hand, could be implemented for multiple types T for the same F, so given F you can't deduce what T is in general.
In practice it is of course very uncommon that multiple Fn traits are implemented for the same type, and when only using closures it's even impossible. However, since it's possible, the compiler needs to account for it.
The signature of the parse method on the Rust's str primitive type is
pub fn parse<F>(&self) -> Result<F, <F as FromStr>::Err>
Why is it not as below?
pub fn parse<F: FromStr>(&self) -> Result<F, F::Err>
I thought perhaps the primitive cast would ensure Err resolves to FromStr::Err, not SomeOtherTrait::Err.
Still, given the following line in the parse documentation...
parse can parse any type that implements the FromStr trait
Why is there no trait bound?
It does use a trait bound, however the bound is specified using the where clause. Look closer:
pub fn parse<F>(&self) -> Result<F, <F as FromStr>::Err>
where
F: FromStr,
<F as FromStr>::Err means the associated Err type from F's implementation of FromStr.
Why is it not as below?
pub fn parse<F: FromStr>(&self) -> Result<F, F::Err>
Because F could implement many different traits, all of which could have a different associated Err type. This syntax makes sure that it gets the type specifically associated with F's FromStr implementation.
We have two traits A and B for which
I can trivially implement B for all types that implement A.
I can trivially implement A for references to any type implementing A.
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?
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.
What Rust construct roughly accomplishes the same thing as the following OCaml?
type t = F : 'x * ('x -> string) -> t
let int_eg = F(1, string_of_int)
let str_eg = F("foo", fun x -> x)
let print x = print_string (match x with
| F(x,to_str) -> to_str x)
The closest thing you can get to existential types are trait objects:
// how ToString is declared
trait ToString {
fn to_string(&self) -> String;
}
let i32_str: Box<ToString> = Box::new(1);
let str_str: Box<ToString> = Box::new("foo");
fn print(value: &ToString) -> String {
value.to_string()
}
print_x(&i32_str); // automatically coerced from Box<ToString> to &ToString
print_x(&str_str);
With trait objects, the actual type is erased, and the only thing that remains is the knowledge that this particular value is of some type which implements the given trait. It is very similar to existential types with type class bounds in Haskell:
data Showable = Showable (forall a. Show a => a)
There is no way to bundle an arbitrary function with an arbitrary type, erasing it from the container signature, so you need to use a trait for it. Fortunately, traits are easy to define and implement for arbitrary types, so you can always define a trait and use a trait object. Trait objects cover almost all functionality for which existentials are usually needed in ML/Haskell.
Moreover, in many cases you don't need to work with trait objects at all! For example, the print() function above should actually be written as follows:
fn print<T: ToString>(value: &T) -> String {
value.to_string()
}
Such function is much more powerful because it works with arbitrary implementors of ToString trait, which include trait objects made out of ToString but also everything else which implements ToString. The only place you usually use trait objects is when you define heterogeneous data structures:
let many_to_strings: Vec<Box<ToString>> = vec![Box::new(1), Box::new("foo")];
But, as I said above, when you consume trait objects, in most cases you don't need to specify that you need a trait object - a regular generic function would be more idiomatic.