I question whether this is really useful at all (ignoring the high implementation cost, for discussion’s sake)? Let’s look at the vanilla derivable types: Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, and Default.
-
Copy and Clone are super useful – so useful that we’ve already special-cased them in the compiler.
-
Debug is vaguely useful, for introspecting the captures? I’d like to see a compelling scenario in which which debug-printing a closure’s captures outside of the closure’s body is useful.
-
PartialEq and Eq are only useful if you’re comparing copies of the same closure by their captures. The least pathological example I can think of is if you had some kind of function like
fn foo(i: i32) -> impl Fn() -> i32 + Eq { move || i }
and tried to compare that they return the same integer… but even this seems pretty silly.
-
PartialOrd and Ord suffer from the same problem – plus, what order are the captures laid out in? This is currently unspecified, which means that the order is some non-canonical, unspecified ordering, which I am skeptical about.
-
Hash would primarially be useful for using closures as keys into a hash table… at which point you should be using opaque tuple structs anyways.
-
Default is essentially useless; to use it, you need a handle on the closure’s type… which you can’t get baring typeof or fn foo<T: Default>(_: T)… which defeat the purpose of Default in the first place.
The serde traits are also just as questionable, since you’d just be serializing the captures, for a type you can’t even name. How do you deserialize something like that? It’s not like you’ll be able to serialize code to send over the network to do RPCs, since the code inside a closure is part of its type. (I admit I am not an expert on how serde works, so feel free to strike that entire paragraph.)
tl;dr I question whether allowing closures to implement complicated traits based on their captures is a good design choice at all.