Currently, there is no syntax for referring to the type of an fn item. So far I think the language has coped well without this, but I'd like to discuss design patterns that could be unlocked if Rust had this feature. I don't have any intention of discussing concrete syntax for naming the type of an fn.
To describe the use case I'm thinking about, I'll start at the other end, where the Fn trait family is used: Higher order functions. I can express that I want some value that implements Fn(), this makes this value callable as a function. Any fn foo() {} will implement Fn() automatically, and can be passed as a value into the higher order function. What makes the Fn family special though, is that it's futile to combine it with other trait bounds: fn higher_order<F: (Fn()) + ArbitraryTrait>(f: F) {}. No value can ever satisfy this kind of bound, because there exists no way to manually implement ArbitraryTrait for fn definitions. The unique fn type exists, but is unnamable.
A concrete use case is a way to bind metadata to functions. For example, imagine an endpoint handler:
This would open up new ways to design APIs in Rust, via cleaner derive-like attribute macros that just implement a given trait for a function item. The advantage is that it makes it possible to associate properties with a function at a place in the file which is local to the function definition, instead of where the function is referenced (with e.g. fn add_endpoint<F: Fn()>(path: &str, f: F)).
The question is whether this is a direction people would want Rust to go in. What other possibilities would it open, and what kinds of anti-patterns would likely appear? Are there fundamental issues that would make this hard to implement in the type system?
I have tried to find "prior art" by searching this forum and github issues. I am unaware of any pre-existing tracking issue or concrete proposal for this feature, the issue tracker is full of semi-related issues and I might easily overlook things when searching.
This doesn't give the ability to add extra trait impls though, since you can never refer to the non-opaque item still (and there is afaik no way to also have the "coerce to fn()" behavior, I wonder if there should be impl Into<fn()> for fn() {foo_impl} generated too).
Which doesn't seem that bad, and also lets people write their own trait implementations not using the macros without needing to wait for implementing Fn to be possible on stable. And to make stateful endpoints that use closures without also needing a way to implement traits for closure types.
So I think I'm far more sympathetic to "it's a pain to use TAITs to get types sometimes; it'd be nice to have sugar for common simple cases" than to sticking random extra impls on function voldemort types.
I think discussing this is unavoidable. Language change discussions are fundamentally about whether the extra complexity from the proposed change is worth making the motivational examples better, compared to the less-convenient ways that already exist.
(Personally not a fan of automatically and conditionally introducing the types/associated types with the same name into the surround namespace, and would be happy with just fn#name, but that's not the main point of the draft.)
My main motivation is a way to "tag" functions. I'm a fan of append-only attribute macros that don't mutate the input syntax, but instead cleanly transform into new sibling top-level items, like #[derive] does. Derive is clean because it (ideally) doesn't clutter the namespace. Because there exists no way to do this for functions, my curiosity is triggered: Is prohibiting this a conscious design decision, or is it just because there hasn't been much demand for a feature like this?
Introducing a new TAIT from a macro invocation is something I'd regard as a more complex and less clean solution - it would make it hard to combine several attributes that all insist on generating the same TAIT.
I see the problem with closures, they will probably not be able to implement anything else than traits from the Fn family. I realize the following argument will probably sound a bit contrived, but: This feature would likely be used when registering callbacks with "framework"-like libraries, which typically (but not necessarily) also would abstract over many possible function signatures. To me this means: The function signature itself is what represents my type: The most precise representation of this type in the type system, is the type of my fn. Since the hypothetical framework would not require any fixed signature, passing a closure might not be a natural thing to do, because I would then have to type-annotate every parameter plus the return type - which doesn't look that good in closure notation (just my opinion!).
Another usecase that I wished was possible several times was being able to name Map<SomeIterator, SomeFixedFunction> as a struct member. I did not want to write a custom iterator type because I used the rayon ParallelIterator implementation.
That usecase will be possible with TAIT (and is relatively low overhead today by just storing a Map<SomeIterator, fn(...) -> _>, a single function pointer is pretty small compared to a lot of other iterator state).
I think the most overhead when using fn(...) -> _ is not due to the function pointer but due to missing inlining. But this depends on the usecase and is a bit offtopic here.
I think the advantage of explicitly namable fn types over TAIT is the readability without requiring naming conventions.