EDIT: I just realized, it also bites when trying to use a Trait Object due to needing Clone, so Box doesn't help in either case, but leaving the question as-is for discussion anyway
You could use the fn() type, which is nameable, Copyable, and Fn()-callable:
foo(None::<fn()>)
But I agree that it is not super pretty. Ideally, non-marker / behavioral-only traits (that is, mainly, traits with just bags of methods) would be auto-implemented for uninhabited types, and then you'd be able to say None::<!> and after monomorphization just get all the code related to that generic parameter and the Some variant Just Disappear™. But correctly defining what is behavioral and what isn't is non-trivial; the least bad option would be to have an magic attribute annotation on traits to mark that.
Until then, the usual option is to have your own empty type for which you implement the required traits, but then in your case you'd still be stuck because of Fn() not being implementable on stable Rust
I think it's worth to distinguish between closures that are short-lived (passed to a function that uses it immediately, then returns) versus closures that are used as callbacks (stored for later in e.g. a struct and called on some event). In Rust, the former is used widely, but the latter is used very little. Generally I find that the kind of closure that is optional is typically of the latter kind.
Yeah, I guess this is rather what people give; generally, making a generic parameter optional does not play well, because of None being compatible with any possible generic type instantiation, thus requiring that the type be specified through some annotation somewhere.
I guess the cases that manage to minimize this impact are builder patterns, since you can make Builder::new() already choose some arbitrary type, and then .with_field(…) allow to override that type with that of the actually provided parameter.
By the way, regarding,
it occurred to me that, especially if using a builder pattern, you can create an uninhabited and yet Fn()-callable type
fn none ()
-> Option<impl 'static + Clone + Fn()>
{
let mut ret = None;
if false {
#[derive(Clone)] enum Uninhabited {}
let _unreachable: Uninhabited = None.unwrap();
ret = Some(move || { let _ = _unreachable; });
}
ret
}
fn main ()
{
assert_eq!(
::core::mem::size_of_val(&none()),
0,
);
}
You'd then stumble upon the limitations of min_type_alias_impl_trait not being stable yet (but soon™), so you may have to use the workarounds showcased in this other post:
In your case, until option 1. becomes stable, I'd go with 3.
as it happens, the framework I'm using is built entirely around the builder pattern, and that's how the API takes event listeners too: DomBuilder in dominator - Rust
it's too much for me to go back and redesign my little state struct things, but will keep my eye out for the future