-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Bare function do not implement trait unless explicitly casted #21086
Comments
I'm getting the same issue, didn't use to have it a short before alpha, can't find out which rev I was when it worked. That case seems simpler I had boiled mine down to: #[allow(unstable)]
extern crate libc;
use libc::{c_void, c_int};
struct State;
trait Push {
fn push_to(state: &mut State, value: Self);
}
type CFun = extern fn(s: *mut c_void) -> c_int;
impl Push for CFun {
fn push_to(_state: &mut State, _value: CFun) {
// do something
}
}
fn main() {
extern fn foo(_s: *mut c_void) -> c_int { 1 }
let mut st = State;
Push::push_to(&mut st, foo); // error: trait `Push` not implemented for ...
Push::push_to(&mut st, foo as CFun); // works!
} |
Link to the pull request where this changed: #19891. |
Oh, so this is intended, should be closed then. |
This is a side effect of the coercions rfc but I think it's terrible. Even though I think it should be possible for the coercion to be implicit. The rationale is that it should be consistent with plain/primitive data types: There are these traits: Int, Float, Fn, ..., and there are these concrete types for instance: i8, i32, f64, fn(), fn() -> i32, ...
Now, when your primary interface for functions are traits it gets a lot harder to do lower level stuff because you don't know the underlying structure for the function so your interaction with it is limited by what the traits let's you do, which is call the function, bah. I'm not saying Fn traits are bad, I think they're great, but it has gotten much more difficult to work with fn() types after they became unique for each function with apparently only a few coercions. I think it's fair for one to be able to implement a certain trait for a fn() but not for a Fn() because that certain impl depends on the concrete type, and the user should not have to coerce a regular function to fn() and the user should also be able to impl that certain trait for whatever type they want. |
I think this could be considered a bug. Functions are coerced to pointers when there aren't generics: fn call(f: fn()) {
f()
}
fn foo() {
println!("foo");
}
fn main() {
call(foo);
} But if you use generics, they are no longer coerced: trait Callable {
fn call(self);
}
impl Callable for fn() {
fn call(self) {
self();
}
}
fn call<F: Callable>(f: F) {
f.call();
}
fn foo() {
println!("foo");
}
fn main() {
call(foo); // error: the trait `Callable` is not implemented for the type `fn() {foo}`
} @nikomatsakis and @eddyb (since you've both worked on this previously), do you think this issue is something we could fix and should be reopened? |
It might be that this is intended since it seems that each function is treated as its own type (and by casting you can get the common function type that the trait is implemented for). I'd still argue it is confusing behavior so maybe the error message should be improved in that case?
(In this case we could do a blanked implemantion over one of the function trait but that does not work for my case, atleast not without #[old_impl_check])
The text was updated successfully, but these errors were encountered: