Conflicting implementation when implementing traits for Fn

I am trying to implement a special trait for all functions that match certain criteria. Unfortunately, the compiler thinks that my trait implementations are conflicting. Here is a link to a minimal example which causes this error. Aren't Fn() -> u32 and Fn(u32) -> u32 supposed to be different types?

I found this project which does something similar, and I have no clue why that version works when mine does not.

Technically Fn(*) -> *, FnMut(*) -> * and FnOnce(*) -> * aren't types at all. They're traits (which aren't types in Rust), and each can refer to a closure including its environment (i.e. its free variables), or it can just refer to a fn item.
This becomes apparent when you want to write a function that takes a closure as an argument e.g.:

fn foo<F>(closure: F) 
where 
    // you can't construct a trait bound using types. 
    // Thus the Fn part is a trait:
    F: Fn(usize) -> usize 
{
    let _closure_output = closure(0);
}

Now that all that's cleared up, I should also mention that you can't implement a trait for another trait.

But what's really tripping up your example is the fact that you're trying to write 2 blanket impls for your Foo trait. I think rustc disallows this because those 2 impls could overlap, at least in principle.

As far as I’m aware, no closure or fn item that you can currently write in stable rust will create an overlapping implementation for Fn() -> u32 and Fn(u32) -> u32. It is however possible in nightly, e.g.:

#![feature(fn_traits)]
#![feature(unboxed_closures)]

#[allow(nonstandard_style)]
struct overloaded_fn;

impl FnOnce<(u32,)> for overloaded_fn {
    type Output = u32;
    extern "rust-call" fn call_once(self, args: (u32,)) -> u32 {
        self.call(args)
    }
}
impl FnMut<(u32,)> for overloaded_fn {
    extern "rust-call" fn call_mut(&mut self, args: (u32,)) -> u32 {
        self.call(args)
    }
}
impl Fn<(u32,)> for overloaded_fn {
    extern "rust-call" fn call(&self, (x,): (u32,)) -> u32 {
        2*x
    }
}

impl FnOnce<()> for overloaded_fn {
    type Output = u32;
    extern "rust-call" fn call_once(self, args: ()) -> u32 {
        self.call(args)
    }
}
impl FnMut<()> for overloaded_fn {
    extern "rust-call" fn call_mut(&mut self, args: ()) -> u32 {
        self.call(args)
    }
}
impl Fn<()> for overloaded_fn {
    extern "rust-call" fn call(&self, (): ()) -> u32 {
        42
    }
}

fn main() {
    println!("{}", overloaded_fn(123));
    println!("{}", overloaded_fn());
}

(playground)

The reason why the implementations of IntoSystem that you linked aren’t overlapping is that they made sure that the implementations of IntoSystem<Params, SystemType> differ in their Params argument, e.g. using different length tuple types, etc.

Since type inference will actually deduce the parameter to the trait in case there is only a single matching implementation, you can probably use the same “trick” for your example

trait Foo<T> {
    fn bar(&self, x: u32) -> u32;
}

impl<F> Foo<(u32,)> for F
    where F: Fn(u32) -> u32
{
    fn bar(&self, x: u32) -> u32 {
        (self)(x)
    }
}

impl<F> Foo<()> for F 
    where F: Fn() -> u32 
{
    fn bar(&self, x: u32) -> u32 {
        (self)() + x
    }        
}

fn main() {
    fn get_5() -> u32 {
        5
    }
    
    let square = |x: u32| x * x;
    
    println!("{}", get_5.bar(10));
    println!("{}", square.bar(2));
}

(playground)

3 Likes

Thanks you so much!

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.