Skip to content

It is no longer possible to implement the same trait for different closures since they became traits #20770

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Nercury opened this issue Jan 8, 2015 · 3 comments
Labels
A-closures Area: Closures (`|…| { … }`)

Comments

@Nercury
Copy link
Contributor

Nercury commented Jan 8, 2015

This worked before. But now there is no way to create different implementations for different closures - meaning this kind of use case goes away.

// Completely contrived example incomming

trait TwoArgClosure<A1, A2, T> {
    fn run_self(&self, a1: A1, a2: A2) -> T;
}

// I can implement this silly trait for 2 arg closure and everything gets
// matched just fine
impl<A1, A2, T, C> TwoArgClosure<A1, A2, T> for C where C: Fn(A1, A2) -> T {
    fn run_self(&self, a1: A1, a2: A2) -> T {
        (self)(a1, a2)
    }
}

// However, the following closure type is considered by compiler to be 
// the same - and I get "conflicting implementations" error
impl<A1, T, C> TwoArgClosure<A1, A1, T> for C where C: Fn(A1) -> T {
    fn run_self(&self, a1: A1, a2: A1) -> T {
        (self)(a1)
    }
}

// Note that leaving out EITHER one of these works... but not both

fn main()
{
    let test_a2 = |&: _: i32, b: i32| b;
    assert_eq!(3, test_a2.run_self(2, 3));

    let test_a1 = |&: a: i32| a;
    assert_eq!(2, test_a1.run_self(2, 3));
}
@Nercury Nercury changed the title It is impossible to differentiate between different closure types when they became traits It is no longer possible to implement the same trait for different closures since they became traits Jan 8, 2015
@milibopp
Copy link
Contributor

milibopp commented Jan 8, 2015

Afaik this is intended behaviour. The problem here are the uniqueness rules. In principle a user could implement both Fn(A1, A2) -> T and Fn(A1) -> T for the same type. Then it would not be clear, how a method call to run_self on such a type should be resolved.

There are workarounds though. You could simply go back to boxing the closure as a trait object or you could wrap the closures in a newtype if you want to avoid the vtable dispatch.

In this context rust-lang/rfcs#493 is probably of interest as it has a more detailed discussion of how one could allow this kind of thing.

@Nercury
Copy link
Contributor Author

Nercury commented Jan 8, 2015

Another alternative would be an implementation of something like Fn(A1) -> T + Closure to constrain the type only for closures that are guaranteed to have single impl.

@arielb1
Copy link
Contributor

arielb1 commented Jul 7, 2015

Seems like intended behaviour to me, now that arguments are associated types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-closures Area: Closures (`|…| { … }`)
Projects
None yet
Development

No branches or pull requests

4 participants