Can non-capturing closures (anonymous functions) be coerced into function pointers?


#1

As far as I understand it, closures are implemented as anonymous structs that wrap captured variables and then implement one of the Fn traits based on inference.

For example, this:

fn main() {
    let my_val = 1i32;

    let print = || println!("{}", my_val);
        print();
}

is equivalent to:


struct AnonymousClosure1<'a> {
    my_val: &'a i32,
}

impl<'a> FnOnce for AnonymousClosure1<'a> {
    type Output = ();

    extern "rust-call" fn call_once(self) -> {
            println!("{}", self.my_val);
        }    
}

fn main() {
    let my_val = 1i32;

    let closure = AnonymousClosure1{
            my_val: &my_val,
        };

        closure();
}

For a closure that doesn’t capture any values, I assume this is still done, but with a unit-struct where:


fn main() {
    let closure = || println!("Hello, world!");
    closure();
}

is roughly equivalent to:


struct AnonymousClosure1;

impl FnOnce for AnonymousClosure1 {
    type Output = ();

    extern "rust-call" fn call_once(self) {
        println!("Hello, world!");
    }
}

fn main() {
    let closure = AnonymousClosure1;
    closure();
}

This seems like a lot of extra generated code for what is essentially an anonymous function. These could, instead, be implemented as bare anonymous functions and coerced to function pointers, which would expand their versatility:

fn anonymous_fn() {
    println!("Hello, world!");
}

fn main() {
    let closure = anonymous_fn;
    anonymous_fn();
    takes_fn_ptr(anonymous_fn);
}

fn takes_fn_ptr(fn_ptr: fn()) {
    fn_ptr();
}

I don’t know if function pointers are very prevalent anymore, since they coerce to closures which most APIs prefer to accept, but there might be some places where they’re still useful. I think FFI might be one of them. If closures could work with FFI, that could be a pretty large ergonomics win for any Rust code integrating with C code that makes heavy use of function pointers. Obviously, capturing closures wouldn’t work, but non-capturing closures (anonymous functions) could.


#2

Function pointers (or function handles as I’d like to call them now) are not very prevalent, see here.


#3

Function pointers are Copy and Clone and are the only way to make clonable iterators while using iterator adaptors like map and filter, because closures are never Clone at the moment, unfortunatly.