Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a closure typed 'extern "C" fn'

Tags:

rust

This is short example about this question.

#[fixed_stack_segment]
fn test(func: extern "C" fn() -> ~str) -> ~str {
    func()
}
extern "C" fn func1() -> ~str {
    ~"hello"
}

fn main() {
    let func2 = || -> ~str { ~"world" };
    println(test(func1));
    println(test(func2));
}

Then, rustc stops with error.

st.rs:13:17: 13:22 error: mismatched types: expected `extern "C" fn() -> ~str` but found `&fn<no-bounds>() -> ~str` (expected extern fn but found fn)
st.rs:13     println(test(func2));

I cannot find a way to make the lambda be an extern fn.

What should I do?

like image 552
Satoshi Amemiya Avatar asked Jan 31 '26 17:01

Satoshi Amemiya


1 Answers

The closure syntax is always either &fn or ~fn, and to make an extern "ABI" fn (for any value of ABI, including Rust), one needs to use a full function declaration.

#[fixed_stack_segment]
fn test(func: extern "C" fn() -> ~str) -> ~str {
    func()
}
extern "C" fn func1() -> ~str {
    ~"hello"
}

fn main() {
    extern "C" fn func2() -> ~str { ~"world" } 

    println(test(func1));
    println(test(func2));
}

There is some talk of allowing lambdas to create non-closures too, with the ABI inferred like anything else in a type signature, but this isn't implemented yet.


However, as Vladimir Matveev says, there is a fundamental difference between closures and normal functions, which means that one will never be able to use all the features of closures when passed as an extern fn. The difference is closures can capture (references to) variables, i.e.

let n = 1;
let f = || { n + 1 }; 

This means a closure is effectively represented by

struct AndFn { // &fn
    env: &Environment,
    func: extern "Rust" fn()
}

struct TwiddleFn { // ~fn
    env: ~Environment,
    func: extern "Rust" fn()
}

where Environment is a struct that contains all the capture variables for that closure (it differs for each &fn, since each one captures different things); the func is a function pointer to the code of the closure, which is what gets executed when the closure is called; if a closure captures any variables, the func will require the env to exist. Thus, the lambda syntax will only be able to create plain extern fns when it captures no variables.

like image 68
huon Avatar answered Feb 03 '26 10:02

huon



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!