The Vale Programming Language

Extern Functions

Vale can call functions written in other languages, such as C. These "external" functions are known as extern functions.

Here, main is calling out into an external C function that reads an int from the keyboard.

The fn readInt() int extern; is telling Vale that the C code will declare a function named readInt.

The C code must declare the function with extern, so it's visible to Vale.

vale
fn main() export {
i = readInt();
println("User entered: " + i);
}

fn readInt() int extern;
c
#include <stdint.h> #include <stdio.h> #include "mvtest/readInt.h" extern ValeInt mvtest_readInt() { int64_t x = 0; scanf("%ld", &x); return x; }
stdin
42
stdout
User entered: 42

Export Functions

The above Vale code called into a C function. The opposite is also possible, C code can call into Vale code. These Vale functions are known as export functions.

Here, a Vale main is calling into a C cFunc function, which is calling into a Vale exported triple function.

Vale automatically provides a header file so C can call the function.

vale
fn cFunc() extern;
fn main() export { cFunc(); }

fn triple(x int) int export {
x * 3
}
c
#include <stdint.h> #include <stdio.h> #include "mvtest/cFunc.h" #include "mvtest/triple.h" extern void mvtest_cFunc() { printf("%ld", mvtest_triple(14)); }
stdout
42

Structs

Recall that a struct can either be an instance or shared. The default is instance. These offer different benefits when calling into (or from) outside code.

Immutable Structs

When we send an immutable struct from Vale into C, we're actually sending a copy. 0

Here, a Vale main function is sending an immutable Mat3 struct into C.

The C code should include "Vec3.h", which is generated by the Vale compiler.

vale
struct Vec3 export imm {
x int; y int; z int;
}

fn main() export {
v = Vec3(10, 11, 12);
s = sum(v);
println(s);
}

fn sum(v Vec3) int extern;
c
#include <stdint.h> #include "mvtest/Vec3.h" #include "mvtest/sum.h" extern int mvtest_sum(mvtest_Vec3* v) { return v->x + v->y + v->z; }
stdout
33

Mutable Structs

We can give C a mutable struct too.

C will receive an "opaque handle", something that points to the struct, but C cannot read its members. It must ask a Vale function to read any members.

The benefit of using mutable structs in externs is that Vale doesn't have to copy the entire thing when we give it to C.

Here, a Vale main function is giving C a reference to a Ship.

The C function halfFuel is then asking the Vale function getFuel what the contained fuel is, so C can do its calculation, and return the result.

vale
struct Ship export {
fuel int;
}

fn getFuel(s &Ship) int export {
s.fuel
}

fn main() export {
s = Ship(42);
h = halfFuel(&s);
println(h);
}

fn halfFuel(s &Ship) int extern;
c
#include <stdint.h> #include "mvtest/Ship.h" #include "mvtest/halfFuel.h" #include "mvtest/getFuel.h" extern int mvtest_halfFuel(mvtest_ShipRef s) { return mvtest_getFuel(&s) / 2; }
stdout
21
Notes
0

Instance structs do not incur this cost. More on that below!