Overview

K is an experimental low-level programming language compiled by klang. It features static type checking, compile time code execution, polymorphic functions, and basic modules with a Rust-inspired syntax. The compiler can either generate simple C code or leverage LLVM for more optimized code generation. Basic test cases and examples of K programs can be found in the test directory of the klang repository.

Polymorphic Functions

Function parameters can be specified as generic types, represented here by the letter T:

fn add(a $T, b T) -> T {
    a + b
}

At each of the function’s call sites, the compiler generates or reuses a specialized definition of the generic function. For example, adding two 64-bit integers (i64) together looks like this:

let x = add(3, 4);
let y = add(x, 5);

The specialized function that is generated for this case:

fn add(a i64, b i64) -> i64 {
    a + b
}

Attempting to use two different types for this example function results in an error:

let z = add(y, 3.14); // Error: types y (i64), 3.14 (f64) do not match

Modules

Types and functions can be defined inside modules, which are similar to namespaces in C++. For example, consider a type Thing defined inside module foo:

module foo {
    struct Thing {
        x i64;
        y i64;
    };

    fn make_thing(x i64, y i64) -> Thing {
        let t Thing;
        t.x = x;
        t.y = y;
        t
    }

    fn do_something(t *Thing) -> i64 {
        t.x + t.y
    }
}

The foo module can be imported and used by external code:

import "foo.k";

fn main() {
    let t0 foo::Thing;
    t0.x = 3;
    t0.y = 5;

    let t1 = foo::make_thing(4, 8);

    let x = foo::do_something(&t0); // x is 8
    let y = foo::do_something(&t1); // y is 12
}

OpenGL Bindings

K provides OpenGL bindings, which are defined and loaded into the gl module in gl.k. An example usage looks something like this:

import "gl.k";

fn main() {
    // Create the OpenGL context and OS window
    let window = gl::create_window("Title", 1280, 720);

    // Load OpenGL function pointers
    gl::load_funcs();

    // Initialize and clear input state
    let input Input;
    for i in 0..256 {
        input.keys[i] = 0;
    };

    gl::ClearColor(1.0, 0.0, 1.0, 1.0);

    // Main loop
    loop {
        gl::poll_events(window, &input);

        // Handle events, simulate...

        gl::Clear(gl::COLOR_BUFFER_BIT);
        // Draw things...
        gl::swap_buffers(window);
    };

    gl::destroy_window(window);
}