Currently if you want to cast “real” (named) function to a function pointer, you have to count out the number of arguments in order to write the type of the fn type on the RHS of the cast. So it'd be something like my_func as fn(_, _, _) -> _. If you don't have the right number of underscores in the arguments list, it won't compile.
It would be handy to allow my_func as fn(..) -> _ to mean “any number of arguments” so that you don't have to write them all out. I think this meshes well with the current language design and would be the way most users who reached for this feature would attempt to spell it.
(A more extreme change in this direction would be to make an even shorter shorthand for function pointers, e.g., my_func as fn->, which would be short — but perhaps too short.)
This may be confusing, because this notation can be interpreted as "function with any number of arguments". I.e. I think this code can be confusing:
fn foo() {}
fn bar(_: u32) {}
let f = if cond {
foo as fn(..) -> _
} else {
bar as fn(..) -> _
};
Is there a point in using a catch-all for arguments, while leaving the possibility to explicitly specify return type? Also there could be some confusion whether we could specify parts of the argument list while omitting others, like with tuples (fn(Foo, .., Bar) -> _). There may also be conflicts if variadic functions are ever added in the future.
That said, there is a unique function pointer type which a function or non-capturing closure could be converted to. So perhaps we could simplify the notation even further, to something like foo as fn?
Whilst foo as fn has its appeal, I think it's important to bear in mind that casting functions with different signatures as fn will result in different types of function pointer—which this proposed syntax particularly masks, and I suspect may lead to confusion.
Right, the primary goal of the proposed syntax is to have something between the underscore in my_func as _ and the function pointer my_func as fn(_, _, _) -> _. fn(..) -> _ is one option, and it fits into the existing syntax (e.g., you could replace the underscore with an actual type). But it would also be nice to have an even shorter syntax that meant “the only kind of function pointer this could possibly be”. I think fn-> is not great, not terrible.
I think my_func as _is the shorthand right now. Where that doesn't work hopefully suggestions in warnings and/or rust analyzer fixups/suggestions can help bridge the gap of manually counting arguments. And when you need to type this a lot hopefully type aliases can help.
Which is all to say you may be highlighting a legitimate need, I'm not sure, but some motivating examples might help delineate the solution space a little better. Especially since fn(..) looks like some tasty syntax to leave open for variable argument functions.
If you're writing a macro, you'll need the invoker to supply the correct function pointer pattern, which is annoying. It would be nice to have some syntax for "cast to function pointer" without knowing anything about its signature.
(That said, I think I'm generally positive on the idea of extending .. to more places. It's come up for allowing foo::<i32, ..>() before too, for example.)
but aiui the way the Fn* traits work around the lack of variadic generics wouldn't extend to a trait like that without some sort of new compiler magic.
as_fn_pointer_trait!(AsFnPointer4; A, B, C, D);
// becomes...
trait AsFnPointer4: Copy {
type A;
type B;
type C;
type D;
type Output;
fn as_fn_pointer(self) -> fn(Self::A, Self::B, Self::C, Self::D) -> Self::Output;
}
impl<A, B, C, D, Output> AsFnPointer4 for fn(A, B, C, D) -> Output {
type A = A;
type B = B;
type C = C;
type D = D;
type Output = Output;
fn as_fn_pointer(self) -> fn(Self::A, Self::B, Self::C, Self::D) -> Self::Output {
self as _
}
}