Skip to content

Axon for C/C++ Developers

If you are coming from C or C++, Axon will feel like a friendlier version of the same underlying machine — but with two big upgrades: a memory-safe type system and AI-native syntax.

C/C++Axon
#include <stdio.h>(extern print_i64 ((_ i64)) void)
int main(int argc, char **argv)(fn main ((argc i64) (argv (ptr (ptr u8)))) i32 ...)
int x = 5;(let (x i32) (i32 5))
int *p = &x;(let (p (ptr i32)) (addr x))
struct Point { int x; int y; };(struct Point ((x i32) (y i32)))
enum Color { RED, GREEN, BLUE };(enum Color (RED) (GREEN) (BLUE))
void *malloc(size_t n)(alloc T) (typed) or (call malloc n) (raw)
void free(void *p)(free p) or (call free p)
printf("%d\n", x);(call print_i64 x)
pthread_t t; pthread_create(&t, NULL, fn, arg);(call spawn (cast (ptr void) arg) fn)
goto cleanup;not supported; use (match ...) or early (return ...)
  • No header files. Axon’s module system is one file per module, and extern declarations are in the language surface itself. There is no #include, no forward declarations, no header guards.
  • No preprocessor. No #define, no #ifdef, no macro expansion. Constants are first-class values; conditional compilation happens at the trait-dispatch level.
  • Memory management is typesafe. (alloc T) returns (ptr T); you cannot accidentally free a ptr T as if it were a ptr U. The compiler tracks the type.
  • Lifetimes are explicit. (ref 'a T) syntax; you cannot use a reference after the data it borrows is freed. The compiler catches it at build time.
  • No undefined behavior. Axon defines behavior for out-of-bounds array access, integer overflow, and null dereference — they panic with a backtrace. There is no “the compiler is allowed to assume you don’t do this” UB contract.
  • No header hell, no ABI mismatch. Every Axon binary statically links the runtime and any dependencies it uses. No -lfoo.so hunting.
  • Compile times are dramatically faster. No templates, no constexpr, no SFINAE. Axon’s whole-program type-checker is sub-second for typical programs.

Computing the GCD of two integers:

C:

#include <stdio.h>
int gcd(int a, int b) {
while (b != 0) {
int t = b;
b = a % b;
a = t;
}
return a;
}
int main(void) {
printf("gcd(12, 8) = %d\n", gcd(12, 8));
return 0;
}

Axon:

(extern print_i64 ((_ i64)) void)
(fn gcd ((a i64) (b i64)) i64
(block
(let (t i64 0)
(while (ne b (i64 0))
(set t b)
(set b (mod a b))
(set a t))
a)))
(fn main () i32
(call print_i64 (call gcd (i64 12) (i64 8)))
(i32 0))

The Axon version is longer because:

  • All locals must be declared with their types ((let (t i64 0))).
  • The compiler needs to know the block’s return type, which block makes explicit.
  • No short-form operators — every operation is a function call.

Note: in (extern print_i64 ((_ i64)) void), the underscore _ is Axon’s wildcard pattern for an unnamed parameter — it tells the type checker “this function takes one i64” without binding it to a name (since extern declarations never reference the parameter inside the body).

The C version is faster to type for an expert C programmer. The Axon version is faster for an LLM to generate correctly because every token is a complete parenthesised form — there’s no operator precedence, no implicit type coercion, no pointer arithmetic.

CAxon
int *p = malloc(sizeof(int) * 4);(let (p (ptr i32)) (call malloc (i64 16)))
p[2] = 99;(store (i32 99) (ptr_add p (i64 8))) — explicit
free(p); p = NULL;(call free p) (set p NULL)
Use-after-freeruntime abort + backtrace
Dangling pointercompile error (lifetime check)

Axon can call C directly:

(extern c_printf ((_ (ptr u8)) ...) void)
(fn main () i32
(call c_printf (str "Hello from C!\n"))
(i32 0))

Compile with the axon-bindgen tool (in axon-debug) to generate extern declarations from a C header file.

Stay in C/C++ for:

  • Hard real-time systems (you need cycle-accurate control)
  • Kernel and driver code
  • Embedded systems with no OS (bare metal)
  • Code that must link against existing C-only libraries

Reach for Axon for:

  • Application-level performance work (servers, data pipelines, ML inference)
  • Anywhere you need memory safety and native speed
  • AI-generated code that needs to ship as a binary
  • Syntax: S-expressions instead of curly-brace expressions. Same machine model underneath.
  • Memory: Type-tracked pointers with explicit lifetimes instead of raw void* + manual free.
  • No preprocessor: Constants are values, not #defined macros. Conditional code uses traits.
  • No undefined behavior: Panics with backtraces instead of compiler-permitted UB.
  • Same compilation target: QBE → native code via clang. You can interop with C libraries via extern.