Why is rust behaving in such illogical way? Those functions have identical prototypes, so why do I need to specify different trait for each of them?!?!?!?
As I understand it, functions each get their own unique type similar to how closures work. These special function types are called "fn items". This helps the compiler do a bunch of optimizations safely, but occasionally causes confusing type errors. Fn items can always be coerced to function pointers, which behave how you'd expect. In many places the coercion is automatic, but type inference gets in the way of the coercion here.
You can coerce the functions to function pointers explicitly if you really want to be able to pass them both as the same type with as fn(&mut Cursive)
This code now looks a bit weird to me. The only way to call this function now is either with the same closure or function twice[1] or with a function pointer. Other options are practically nonexistent since Copy prevents boxed trait objects (FnOnce or similar) or mutably borrowed trait objects, and &dyn Fn(...) is mostly ruled out by the 'static.
So either, the separate parameter F3 should be kept, or the function can be made fully monomorphic to always expect function pointers. (The choice depends on whether capturing closures [capturing Copyable data] should be allowed, and - more importantly - on whether the monomorphization for each given pair of function types, and avoiding dynamic function calls, is seen as a relevant performance benefit.) As a positive side effect, either approach would make the calls-site straightforward again.
which I assume is not supposed to be a common use case here, but maybe I'm wrong? ↩︎
What do you mean by the only option is to call it twice? If I call show_cpy_dlg_cb, the show fn will get called and not twice nor will the hide fn get called either.
You're missing the “or with a function pointer” that ends that sentence in that quote. (Just making sure you didn't overlook that.)
In case it was too sloppily formulated: “called with the same ... twice” is supposed to mean “called with two copies of the same ... as the two arguments”.
The code from @semicoleon by the way demonstrates the approach of using function pointers, so the “same closure twice” doesn't apply.
Maybe focus on my conclusion first, if I didn’t present the argument (leading to that conclusion) well enough:
The point is that the use-case of using function pointers is (essentially) the only use-case left (except for those where two copies of the same function/closure are passed). So if only function-pointers are to be used anyways, the signature could as well be written
To further explain the argument, in case the rest was not clear enough before, either: For closures and fn items, if the types are the same then the closure/function is the same, too, which is a not too useful case. The only implementors of FnOnce besides closures and fn items are
function pointers
dyn FnOnce/dyn FnMut/dyn Fn trait objects
Box<T>, &mut T, &T for T being any of these cases (possibly recursively)
The additional bounds rule out most of those. The Copy bound rules out Box<T> and &mut T, and the 'static bound rules out (most reasonable cases) of &T, too.The trait objects can never be passed alone, so by Box<T>, &mut T, &T being eliminated, they are out of the equation, too; thus only function pointers are left.
(And technically something like &'static dyn Fn(…) would work, too, but I would have never seen such a thing before.)