Heroes / Examples / 08-ffi

examples/gallery/08-ffi.hero

Use C libraries for features beyond the language basics.

extern declares calls to C libraries for maths, files, network connections and databases. The clang compiler checks those declarations against the library’s header, the file that describes its functions and types. It reports incompatible types before the program runs.

Run it

$ heroes run examples/gallery/08-ffi.hero

These files introduce the language one feature at a time. This page shows the program and not a result, because no test compares their output byte for byte yet.

The program

## Everything else comes from C
#
# There is no standard library, permanently. Maths beyond arithmetic,
# files, sockets, databases: they arrive through `extern`, and clang checks
# every declaration against the real header — a wrong type here is a
# compile error, not a crash at runtime.
#
# A group names the header its signatures come from. That is not decoration:
# the header is what clang checks against, and without one a declaration
# would be verified by nothing at all.

extern "math.h" link "m"
    function sqrt(x: f64) -> f64
    function pow(base: f64, exponent: f64) -> f64
    function floor(x: f64) -> f64

# `cstr` is a C string and `ptr` an opaque pointer. Neither is a `str`:
# the boundary is visible in the type. A second group, because this one
# comes from a different header — and on macOS neither needs `link`, since
# libm and libc are already there.
extern "stdio.h"
    function puts(s: cstr) -> i64

# The hypotenuse, in the language's own arithmetic plus one C call.
#
# Both sides are `f64`, so §4.9 makes the names mandatory at the call site. C's
# numeric APIs are where same-typed parameters cluster — `pow(base:, exponent:)`
# is the same shape — so this is where the rule is felt most and where argument
# inversion would be silent without it.
function hypotenuse(a: f64, b: f64) -> f64
    return sqrt(a * a + b * b)

# No implicit conversions: an `i64` becomes an `f64` because you said so.
function diagonal_of(width: i64, height: i64) -> f64
    return hypotenuse(a: to_f64(width), b: to_f64(height))

# `pow` is C's, `floor` is C's, and the rounding is yours.
function rounded_power(base: f64, exponent: f64) -> i64
    return to_i64(floor(pow(base: base, exponent: exponent))).must()

test "the C library does the maths"
    assert hypotenuse(a: 3.0, b: 4.0) == 5.0
    assert rounded_power(base: 2.0, exponent: 10.0) == 1024

function main()
    print(
        "the 16:9 diagonal of a 1920-wide screen: ",
        diagonal_of(width: 1920, height: 1080)
    )
examples/gallery/08-ffi.hero, 49 lines

fingerprint sha256 1c123e67ca74 · 1 file · index.json

Next: 09-holes. All the examples. ← Previous: 07-strings

Run one yourself: the four commands. Learn the language, or read the full specification in one file.