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.
What’s identical
Section titled “What’s identical”| 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 ...) |
What’s different
Section titled “What’s different”- No header files. Axon’s module system is one file per module, and
externdeclarations 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 accidentallyfreeaptr Tas if it were aptr 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.sohunting. - Compile times are dramatically faster. No templates, no constexpr, no SFINAE. Axon’s whole-program type-checker is sub-second for typical programs.
Code Comparison
Section titled “Code Comparison”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
blockmakes 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 (sinceexterndeclarations 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.
Pointer safety
Section titled “Pointer safety”| C | Axon |
|---|---|
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-free | runtime abort + backtrace |
| Dangling pointer | compile error (lifetime check) |
FFI interop
Section titled “FFI interop”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.
When to stay in C/C++ vs reach for Axon
Section titled “When to stay in C/C++ vs reach for Axon”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
Summary for C/C++ Veterans
Section titled “Summary for C/C++ Veterans”- Syntax: S-expressions instead of curly-brace expressions. Same machine model underneath.
- Memory: Type-tracked pointers with explicit lifetimes instead of raw
void*+ manualfree. - 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.