The Problem
If you want to implement a trait "for closures", you have to write a blanket impl, roughly like this:
impl<F: FnOnce(bool) -> String> MyTrait for F { ... }
The problem with these kinds of impls is that they could apply to every type, thus causing a lot of problems with coherence and orphan rules. This is something I encountered a lot already. The solution often involves creating a wrapper that contains the closure and then implementing the trait for Wrapper<F>
. It works, but is not optimal: the wrapper has to be added to the API and users have to wrap their closures into that wrapper to use it as MyTrait
.
Just to give a specific example, in one crate I'm developing right now, I have something similar to this:
trait Map<Key> {
type Value;
fn get(&self, key: Key) -> Self::Value;
}
impl<Key, Value> Map<Key> for std::collections::HashMap<Key, Value> { ... }
// That would be useful:
impl<Key, Value, F: Fn(Key) -> Value> Map<Key, Value> for F { ... }
It would be really useful to also implement the trait for closures, but this leads to the coherence problems mentioned above. For example, with above closure impl it's not possible anymore to to implement the trait for &T where T: Map<Key, Value>
, which is a super useful impl as well. It gets even worse when other crates want to implement Map
for their own types.
So I had to do this:
struct FnMap<F>(F);
impl<Key, Value, F: Fn(Key) -> Value> Map<Key, Value> for FnMap<F> { ... }
Again, it works, but now I have FnMap
in my API and users always have to import FnMap
and wrap their closure in it. Absolutely not optimal!
The idea
We could add such a wrapper to libcore already. For example, core::ops::Closure
(the specific module path is not important right now, though). It would be roughly defined as:
#[derive(Clone, ...)]
pub struct Closure<F>(F);
// Implement `Fn*` traits by passing through to `F`
impl<Args, F: FnOnce<Args>> FnOnce<Args> for Closure<F> { ... }
impl<Args, F: FnMut<Args>> FnMut<Args> for Closure<F> { ... }
impl<Args, F: Fn<Args>> Fn<Args> for Closure<F> { ... }
But the main part of the idea is that a closure expression |...| ...
would automatically "result" in Closure<F>
. That way the user does not need to wrap it themselves. I see two ways to do that:
- When generating the closure type, the compiler actually just wraps it into
Closure
automatically. This would mean that all closure expressions would have a typeClosure<F>
, whereF
is the anonymous generated type. - Closure types could automatically coerce to
Closure<F>
. I'm not sure if this is better or worse, but it would be possible.
What would this idea solve?
Well, for one, it is backwards compatible. Since Closure<F>
also implements all traits that F
implements, and all existing usages of closures are fully generic, wrapping closures into Closure
would just work. I also thought about non-capturing closures that coerce to function pointers, but I don't think this would be a problem.
With this, traits could be implemented for Closure<F>
instead of just F
, solving the issues with coherence and orphan rules. This makes handling closures a lot less annoying in many situation, IMO.
Feedback
What do you think? Anything important I missed? Do you also think this problem is worth solving somehow or have you never encountered it? Additional ideas?