Option<Fn> fails to compile

I previously suggested an approach involving an uninhabited closure type, and a helper function which can make the call both shorter and arguably more efficient (since the Option<…> becomes zero-sized).

Applied to this case, and updated to work with edition 2021, it looks something like

#[inline]
pub fn nop<T>() -> Option<impl FnMut(T) -> Result<(), Box<dyn Error>>> {
    enum Void {}
    None::<Void>.map(|void| move |_: T| {
        let _ = &void; // edition 2021 closure capture workaround
        match void {}
    })
}

fn main() -> Result<(), Box<dyn Error>> {
    let ncb = |_n: Node| -> Result<(), Box<dyn Error>> { Ok(()) };
    let wcb = |_w: Way| -> Result<(), Box<dyn Error>> { Ok(()) };
    let rcb = |_r: Relation| -> Result<(), Box<dyn Error>> { Ok(()) };

    map_all(Some(ncb), None::<fn(_) -> _>, Some(rcb))?;
    map_all(Some(ncb), nop(), Some(rcb))?; // shorter to call, and the type is smaller :-)

    Ok(())
}

Rust Playground


Depending on the use-case, i.e. on how these closures are used, in case that None is merely handled by doing nothing whilst the Some case has the closure called, you might also be able to avoid the need for Option entirely, instead just expecting the user to pass some no-op closure (possibly aided by a similar convenience function if that’s considered nicer than having to write the closure manually).

If the choice between Some vs. None does change behavior in different ways, this would not work of course.

1 Like