error[E0277]: the trait bound `Box<dyn Fn()>: From<[closure@src/main.rs:44:14: 44:18]>` is not satisfied
--> src/main.rs:44:9
|
44 | foo.push(||{});
| ^^^^ the trait `From<[closure@src/main.rs:44:14: 44:18]>` is not implemented for `Box<dyn Fn()>`
|
= help: the following implementations were found:
<Box<(dyn std::error::Error + 'a)> as From<E>>
<Box<(dyn std::error::Error + 'static)> as From<&str>>
<Box<(dyn std::error::Error + 'static)> as From<Cow<'a, str>>>
<Box<(dyn std::error::Error + 'static)> as From<String>>
and 22 others
= note: required because of the requirements on the impl of `Into<Box<dyn Fn()>>` for `[closure@src/main.rs:44:14: 44:18]
But I don't want to use Box::new at push explicitly, then I defined Into2 trait as follow:
The problem is that Box<dyn Fn()> itself implements Fn(). The two implementations of Into2 you have are conflicting because theyβre overlapping, this doesnβt mean that
no, but Box<dyn Fn()> is a particular special case of impl Fn().
The problem is that you have two blanket impls. One of them has no bounds β it is provided for every type. Including those types that are covered by the other one with the Fn() bound. Which impl should "win" if a type satisfies both?
It does not. Looking at this list of impls, the only Box<dyn Trait> types from the standard library that implement this conversion are Box<dyn Error> and Box<dyn Error + Send + Sync>.
But the problem is, impl<T> Into2<T> for T and impl<F:Fn()> Into2<Box<dyn Fn()>> for F is not equal. Even Box may impls Fn() as well, above expression are translate into impl<T> Into2<Box<T>> for Box<T> and impl<T> Into2<Box<Box<T>> for Box<T> respectively, they should not conflict as well.
The conflict is when F and T are both Box<dyn Fn()>.
Substituting T == Box<dyn Fn()> into the first impl
impl<T> Into2<T > for T
ββββββββββββββββββββββββββββββββββββββββββββββ
impl Into2<Box<dyn Fn()>> for Box<dyn Fn()>
Substituting F == Box<dyn Fn()> into the second impl
impl<F> Into2<Box<dyn Fn()>> for F
ββββββββββββββββββββββββββββββββββββββββββββββ
impl Into2<Box<dyn Fn()>> for Box<dyn Fn()>
// and the where clause
where
F : Fn(),
ββββββββββββββββββββββββ
where
Box<dyn Fn()>: Fn(), // β this trait bound is true
So you have an impl Into2<Box<dyn Fn()>> for Box<dyn Fn()> as a special case for each of the impls; thatβs the conflicting case.
conflicting implementation for `std::boxed::Box<(dyn std::ops::Fn() + 'static)>`
i.e. itβs telling: thereβs a conflict for Self == Box<dyn Fn()>.
How does it know this? Well, weβd have to try to make
impl<T> Into2<T> for T
and
impl<F> Into2<Box<dyn Fn()>> for F
where
F: Fn(),
βlook the sameβ in some special case. In general if you want
impl Into2<Foo> for Bar
and
impl Into2<Baz> for Qux
to βlook the sameβ, you need to have Foo == Baz and Bar == Qux in order to succeed. So for
impl Into2<T> for T
and
impl Into2<Box<dyn Fn()>> for F
(i.e. ignoring the <T> or <F> variable binding and the where clause)
we need T == Box<dyn Fn()> and T == F. So thatβs how you can (and how I have, and the compile has) figure(d) out the assumption that ultimately leads to an overlap, i.e. the assumption that F and T are both Box<dyn Fn()>. Making sure that this is actually an overlap is what my previous post demonstrates. The general process of finding these equations is known as unification, the compiler uses variants of unification internally for type inference, and trait resolution and trait coherence checks (and probably other things as-well).
Thanks for your patience and time! I've learnt a lot from your reply. But additionally, within my knowledge, Rust cannot implement a trait for a group of types except some specific types, I mean, I cannot NOT implement Into2<Box<dyn Fn()>> for Box. Why Rust not support or it may added in the future?
Negative impls complicate the trait system immensely, and they interact particularly badly with some planned or existing features (e.g. specialization).
Indeed writing a set of impls like you want will probably become possible in the future. (Though not necessarily by explicitly removing some type from an impl, as @H2CO3 mentioned above.) There are a few unstable features that allow you to create an overlapping implementation like this (and resolve the overlapping case explicitly).
Obviously, weβll want to use the approach of doing nothing for Into2<Box<dyn Fn()>> for Box<dyn Fn()> rather than unnecessarily adding an extra layer of Box. On the other hand, note that this can have some potentially confusing consequences as-well such that Into2<Box<dyn Fn()>> for Box<dyn Fn() + Send>still adding another Box. (You could try to eliminate these cases, too, but it becomes tedious.)
#![feature(specialization)]
#![feature(marker_trait_attr)]
#![allow(incomplete_features)]
struct Foo<T>(Vec<T>);
impl<T> Foo<T> {
fn push<U: Into2<T>>(&mut self, u: U) {
self.0.push(u.into2());
}
}
trait Into2<T> {
fn into2(self) -> T;
}
fn main() {
let mut foo = Foo(Vec::<Box<dyn Fn()>>::new());
foo.push(|| {});
}
impl<T> Into2<T> for T {
fn into2(self) -> Self {
self
}
}
// we want add this impl effectively:
//
// impl<'a, F: Fn() + 'a> Into2<Box<dyn Fn() + 'a>> for F {
// fn into2(self) -> Box<dyn Fn()> {
// Box::new(self)
// }
// }
#[marker]
trait Into2Marker<T> {}
impl<'a, F: Fn() + 'a> Into2Marker<Box<dyn Fn() + 'a>> for F {}
impl<T> Into2Marker<T> for T {}
impl<S, T> Into2<S> for T
where
T: Into2Marker<S>,
{
default fn into2(self) -> S {
<_>::into2_helper(self)
}
}
trait Into2Helper<T> {
fn into2_helper(this: Self) -> T;
}
impl<S, T> Into2Helper<S> for T {
default fn into2_helper(_this: Self) -> S {
unreachable!("always specialized")
}
}
impl<F: Fn() + 'static> Into2Helper<Box<dyn Fn()>> for F {
fn into2_helper(this: Self) -> Box<dyn Fn()> {
Box::new(this)
}
}
// demonstration
fn _first_demo<'a, F: Fn() + 'a>(f: F) -> Box<dyn Fn() + 'a> {
// for some reason `f.into2()` called directly (without explicitly giving the types) doesnβt work
<F as Into2<Box<dyn Fn() + 'a>>>::into2(f)
}
fn _second_demo<T>(x: T) -> T {
x.into2()
}
Note that specialization is a very WIP feature with lots of open problems. (Iβve also seem other proposals suggesting the need for a new feature in Rust, related to specialization, but only for handling (and disambiguating) overlapping trait impls.)
The above approach is quite cumbersome and combines multiple unstable features in a stable way (and for some reason doesnβt work flawlessly nonetheless, as you can see in the demonstration code). This is just addressing the setting of one trait and two specific impls. While, as demonstrated, creating such an impl may become possible in the future, itβs a different question whether youβll ever be able to do it for the Into trait itself.