adam-mcdaniel/oakc

extern keyword

Closed this issue · 1 comments

If possible, I would like to get rid of explicit foreign function calls. I think the following solution would be more elegant for typechecking.

Instead of using foreign_func!() to call a foreign function, I would like to introduce the extern keyword. It's usage would look like this.

#[if(TARGET == 'c') {
    #[extern("mem.c")]
    // Optimized versions of memcpy & memset in C
    extern __oak_memcpy as memcpy(dst: &char, src: &char, size: num) -> void; // You can specify a return type
    extern __oak_memset as memset(dst: &char, val: char, size: num);
    // Choose not to rename foreign function
    extern prend();
} else {
    fn memcpy(dst: &char, src: &char, size: num) {
        for i in 0..size {
            dst[i] = src[i];
        }
    }

    fn memset(dst: &char, val: char, size: num) {
        for i in 0..size {
            dst[i] = val;
        }
    }

    fn prend() { putchar('\n') }
}]

Here, if we use the C target, we grab the foreign functions __oak_memcpy, __oak_memset, and prend and give them Oak type signatures. memcpy would expand to the following at compile time.

// This is what the compiler generates, and it's what we would have written before.
fn memcpy(dst: &char, src: &char, size: num) {
    __oak_memcpy!(dst, src, size)
}

This looks much better, and it also abstracts away foreign functions from the user. Lets say you're using a library that uses foreign functions. You could use them without any typechecks just by calling them directly with the ! operator. With the extern keyword, though, typechecks are possible.

That looks way better. So this essentially generating typed wrapper functions instead of having to write those yourself right? This does still require the foreign function to know about the oak abi and provide the bridge to its native abi, but that is probably out of scope of the current issue.