Skip to content
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

Expand implicit conversion of functions to function pointers #58078

Open
Thomasdezeeuw opened this issue Feb 2, 2019 · 5 comments
Open

Expand implicit conversion of functions to function pointers #58078

Thomasdezeeuw opened this issue Feb 2, 2019 · 5 comments
Labels
A-coercions Area: implicit and explicit `expr as Type` coercions A-trait-system Area: Trait system C-feature-request Category: A feature request, i.e: not implemented / a PR. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@Thomasdezeeuw
Copy link
Contributor

(I'm not sure if this requires a RFC, if so please let me know.)

Allow implicit conversion of functions to function pointers when trait is implemented on a function pointer. The code below shows the problem I'm having.

Calling accepts_fn works fine today, however calling accepts_my_fn doesn't work, even though the MyFn trait is implementation for function pointers. To make it work a explicit conversion (as fn(_) -> _) is required. This seems a bit surprising that in one instance a function in implicitly converted and another instance it is not.




fn add1(n: usize) -> usize {
    n + 1
}

fn accepts_fn(f: fn(usize) -> usize) -> usize {
    f(1)
}

trait MyFn {
    fn call(&mut self, n: usize) -> usize;
}

impl MyFn for fn(usize) -> usize {
    fn call(&mut self, n: usize) -> usize {
        (self)(n)
    }
}

fn accepts_my_fn<F: MyFn>(mut f: F) -> usize {
    f.call(2)
}

fn main() {
    let n = accepts_fn(add1);
    println!("n: {}", n);
    
    // This doesn't work.
    //let n = accepts_my_fn(add1);
    
    // We need explicit conversion.
    let n = accepts_my_fn(add1 as fn(_) -> _);
    println!("n: {}", n);
}

(playground)

@jonas-schievink jonas-schievink added the C-feature-request Category: A feature request, i.e: not implemented / a PR. label Feb 2, 2019
@Centril Centril added T-lang Relevant to the language team, which will review and decide on the PR/issue. A-coercions Area: implicit and explicit `expr as Type` coercions A-trait-system Area: Trait system labels Feb 3, 2019
@Thomasdezeeuw
Copy link
Contributor Author

Can someone tell if this change would require a RFC?

@Thomasdezeeuw
Copy link
Contributor Author

I still like some feedback on if this is wanted or not. If I could get some guidance I'm willing to write a pr for it.

@CodeSandwich
Copy link

CodeSandwich commented Jun 21, 2019

There's one more point to add. Let's rename MyFn::call to MyFn::call_fn to avoid confusion with existing traits. Calling call_fn directly is impacted in the same way:

// doesn't work
add1.call_fn(5);
// works, but at what cost
(add1 as fn(_) -> _).call_fn(5);

I have the same problem, which I'm struggling with. Current coercion rules make APIs based on functions as first-class citizens barely usable.

PR would be probably very welcome. Unfortunately I can't say how hard will it be to actually implement if possible at all.

I think that core problem is that Rust makes only 1-step coercions for non-deref coercions. Fn items can coerce to fn pointers, fn pointers can coerce to trait implementors, but fn items can't make 2 steps and coerce to trait implementor directly. If that's really the case, #18602 should solve it.

@QuineDot
Copy link

I think it's more that trait resolution doesn't fall back to consider implementations for types you could coerce to (no function items implement your trait.) It's not specific to function items and function pointers; compare here, where no arrays implement the trait.

For the function item / function pointer example, this change

-impl MyFn for fn(usize) -> usize {
+impl<F> MyFn for F where F: Fn(usize) -> usize {

Implements the trait for function items as well, allowing the un-casted version to compile.

@Thomasdezeeuw
Copy link
Contributor Author

For the function item / function pointer example, this change

-impl MyFn for fn(usize) -> usize {
+impl<F> MyFn for F where F: Fn(usize) -> usize {

This doesn't work once the arguments or return types are also generic due to "unused generic" errors. Otherwise it would be my preferred implementation as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-coercions Area: implicit and explicit `expr as Type` coercions A-trait-system Area: Trait system C-feature-request Category: A feature request, i.e: not implemented / a PR. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants