Satoshi Amemiya
Satoshi Amemiya

Reputation: 33

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

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?

Upvotes: 3

Views: 3318

Answers (1)

huon
huon

Reputation: 102066

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.

Upvotes: 4

Related Questions