Metaprogramming

Banjo provides compile-time features through the meta system. Meta expressions and statements are evaluated at compile-time, generating runtime code. These constructs can only access compile-time values like const values or type information.

The size of a type can be accessed using meta(T).size:

struct User {
    var id: u32;
    var name: String;
}

func main() {
    println(meta(i32).size);  # 4
    println(meta(f64).size);  # 8
    println(meta(User).size);  # 32 on 64-bit targets
}

Type Reflection

You can access the name of a type as well as its fields using meta(T) expressions:

struct Circle {
    var x: f32;
    var y: f32;
    var radius: f32;
    var color: u32;
}

func main() {
    println(meta(Circle).name);  # "Circle"

    var circle = Circle {
        x: 10.0,
        y: 5.0,
        radius: 3.5,
        color: 0xFF0000FF,
    };

    # "x: 10, y: 5, radius: 3.5, color: 4278190335;"
    meta for field in meta(circle).fields {
        print(field.0);
        print(": ");
        print(field.1);
        print("; ");
    }

    println("");
}

meta if

Conditions can be evaluated at compile-time using meta if statements:

use std.config;

meta if config.OS == config.EMSCRIPTEN {
    use web;

    func load_asset(name: StringSlice) -> Array[u8] {
        return web.download_file(name);
    }
}

std.config

The standard library features a built-in module called std.module that provides information about the current build. These constants are currently available:

Name

Description

Values

BUILD_CONFIG

Build configuration

DEBUG, RELEASE

ARCH

Target architecture

X86_64, AARCH64, WAS

OS

Target operating system

WINDOWS, LINUX, MACOS, EMSCRIPTEN