Inferred type of a function assigned to an untyped variable

I thought that, unlike closures, functions have well-defined types, like fn(), which is the same as fn() -> (), fn(bool, u8) -> (bool, u16) etc . (And similar for unsafe fn, like unsafe fn(), unsafe fn(bool, u8) -> (bool, u16) etc.)

But, when I assign a function identifier/path to an untyped variable, it has some other (unique?) type, as mentioned in this error:

no method named use_it found for fn item fn() {zero_args_unit} in the current scope

pub trait ZeroArgsUnitFnTrait {
    fn use_it(&self) {}
}

type ZeroArgsUnitFnType = fn();
impl ZeroArgsUnitFnTrait for ZeroArgsUnitFnType  {}

fn zero_args_unit() {}

// Compiles
fn assign_fn_to_typed_var() {
    let f: fn() -> () = zero_args_unit;
    f.use_it();

    let f: ZeroArgsUnitFnType = zero_args_unit;
    f.use_it();
}

// Fails to compile
fn assign_fn_to_untyped_var() {
    let f = zero_args_unit;
    f.use_it();
}

// Fails to compile
fn direct_no_assign() {
    zero_args_unit.use_it();
}

Are those actual unnamed types accessible somehow, or can I at least implement trait(s) for them somehow (ideally separately for safe and unsafe ones, or just limiting to safe ones)? Or what are such types called and where can I read about them?

Or, a more specialized problem, please: How can I detect at compile time (in macro_rules!) whether a given function is safe (rather than unsafe), but without a compiler error. Or, rather, how do I ensure that a given function actually is not safe, but unsafe (and issue a compile error is the function is safe)? (I cannot use #[forbid(unused_unsafe)] and then unsafe {...}, because instead of a function identifier/path I may be given an expression that yields the function, and the actual expression itself may include unsafe{...}).

See Function item types - The Rust Reference

1 Like

You can't name function item types directly, but you can implement for a generic F: Fn() or similar. I'm fairy certain that would be the safe ones only -- I'm on mobile currently but it would be easy to confirm.

Function item types are unique, like closure types, and zero sized, like non-capturing closures. In contrast types like fn() are function pointers.

1 Like

Obligatory link to Logan Smith's Rust Functions Are Weird (But Be Glad) video that goes in depth into why function items have different types and what optimisations this enables.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.