Does `impl Fn()` implemented `Into<Box<dyn Fn()>>`?

Here is my code:

struct Foo<T>(Vec<T>);
impl<T> Foo<T>{
    fn push<U:Into<T>>(&mut self,u:U){
        self.0.push(u.into());
    }
}

fn main(){
    let foo=Foo(Vec::<Box<dyn Fn()>>::new());
    foo.push(||{});
}

I ran cargo b, but it printed an error:

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:

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;
}

impl<F:Fn()+'static> Into2<Box<dyn Fn()>> for F{
    fn into2(self)->Box<dyn Fn()>{
        Box::new(self)
    }
}

fn main(){
    let mut foo=Foo(Vec::<Box<dyn Fn()>>::new());
    foo.push(||{});
}

It works this time, but when I added this:

impl<T> Into2<T> for T{
    fn into2(self)->Self{
        self
    }
}

Unexpectedly it printed another error:

error[E0119]: conflicting implementations of trait `Into2<std::boxed::Box<(dyn std::ops::Fn() + 'static)>>` for type `std::boxed::Box<(dyn std::ops::Fn() + 'static)>`
  --> src/main.rs:52:1
   |
46 | impl<F:Fn()+'static> Into2<Box<dyn Fn()>> for F{
   | ----------------------------------------------- first implementation here
...
52 | impl<T> Into2<T> for T{
   | ^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `std::boxed::Box<(dyn std::ops::Fn() + 'static)>`

What? Did it means impl Fn() is equivalent to Box<dyn Fn()>? If it is, why can't I convert impl Fn() into Box<dyn Fn()> by using into?

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().

2 Likes

No. They are definitely not equivalent.

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?

Does impl Fn() implemented Into<Box<dyn Fn()>>?

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>.

I suggest you use:

trait IntoBox<T : ?Sized> {
    fn into_box (self)
      -> Box<T>
    ;
}

impl<T> IntoBox<T> for T {
    fn into_box (self: T)
      -> Box<T>
    {
        Box::new(self)
    }
}

impl<'lt, F> IntoBox<dyn 'lt + Fn()> for F
where
    F : 'lt + Fn(),
{
    fn into_box (self: F)
      -> Box<dyn 'lt + Fn()>
    {
        Box::new(self)
    }
}

instead :slightly_smiling_face:

(or just your Into2 trait, but without the reflexive impl)

@Fancyflame By the way, (as a somewhat unrelated note:) with this knowledge you can explain, why the implementation of Error for Box<T>

impl<T: Error> Error for Box<T>

doesn’t support unsized types: It would lead to the same problem.

Thanks I got it. I just forgot Box may impls Fn() as regular functions do :joy:. But I'm thinking how to impl Into<Box<dyn Fn()>> for impl Fn()

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.

Here’s the details:

you have

impl<T> Into2<T> for T

and

impl<F> Into2<Box<dyn Fn()>> for F
where
    F: Fn(),

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.

2 Likes

By the way, the compiler calls out this 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. :smiley: 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.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.