PatLang for C Programmers
C gives you manual control over every byte and every allocation. PatLang gives you none of that control back, deliberately — there are no pointers, no malloc/free, and no way to reach past the language into raw memory. What C programmers will find interesting is what PatLang does expose in place of that control: an exact numeric tower instead of fixed-width integer wraparound, and — underneath the interpreter and the native compiler both — a real Rust runtime, which is a language C programmers can generally read even before learning PatLang itself.
The quick mental model
PatLang is memory-managed automatically (the interpreter and every compiled-output path are built in Rust, and PatLang programs never see a raw pointer or manage an allocation themselves). Values are copy-by-default (assigning or passing a list conceptually copies it) with an opt-in escape hatch — handle-based mutable builders — for the cases where that copying would actually cost you something. There's no preprocessor, no header files, no manual linking step for ordinary programs (rustc only appears as an internal backend PatLang's own compilers shell out to; you never invoke it directly for user programs compiled with patc1).
Syntax, side by side
/* C */
int add(int a, int b) {
return a + b;
}
int x = 5;
if (x > 0) {
printf("positive\n");
} else if (x < 0) {
printf("negative\n");
} else {
printf("zero\n");
}
int i = 0;
while (i < 10) {
i++;
}
# PatLang
make a function called add takes a, b returns sum
return a + b
end
let x = 5
if x > 0 then
print("positive")
elif x < 0 then
print("negative")
else
print("zero")
end
let i = 0
while i < 10 do
let i = i + 1
end
No type declarations on parameters, return values, or variables — everything is just a name. No semicolons required. No header/source split, no forward declarations: a function is visible anywhere in a compiled unit once the file (or anything it includes) has been read.
There is no manual memory management, at all
This is the single biggest shift coming from C. There's no malloc/free/realloc, no pointers, no pointer arithmetic, no NULL dereference to guard against, no use-after-free, no manual buffer sizing. Every PatLang value is managed for you by the Rust runtime underneath — you genuinely cannot get at raw memory from PatLang source, by design.
What you get in exchange is a real, if less granular, performance-vs-clarity choice: ordinary let-bound lists and strings are value semantics — reading or passing one conceptually copies it, which is what made the self-hosted compiler's early tokenizer accidentally O(n²) before it switched to handle-based builders. Those handle-based builders (vec_new/vec_push/vec_set/vec_get for mutable vectors, sb_new/sb_push/sb_str for string builders, str_intern for read-only interned strings) are PatLang's closest equivalent to C's "just mutate the buffer in place" — an explicit choice you make when copying would actually cost you something, not the default. See Handle-based vs list-based collections.
Things C has that PatLang doesn't
- No pointers, no addresses, no pointer arithmetic. There's simply nothing in PatLang that corresponds to
&xor*p. - No fixed-width integer types (
int8_t,uint32_t, etc.) and no integer overflow wraparound — a number that outgrows a machine word promotes to an arbitrary-precisionBigIntautomatically instead. See the Numeric Tower section. - No structs, no unions, no manual memory layout control. The closest thing to packed binary layout is the bitfield helper functions (
bit_get/bit_set/bit_slice/bit_set_slice) operating on a plain integer — see the bitwise & bitfields demo — not a real layout-controlled type. - No preprocessor. The closest equivalent to
#includeisinclude "relative/path.patlang", a simple textual splice with no macro expansion. - No
forloop, nobreak/continue, noswitch. Onlywhileandif/elif/else; structure early-exit logic with a boolean flag. - No manual compilation pipeline to reason about. There's no separate preprocess/compile/assemble/link you control —
rustcis an internal detail PatLang's own compilers invoke on your behalf.
What PatLang has that C doesn't
- An exact numeric tower — integer overflow promotes to
BigInt, uneven integer division promotes to an exactRationalrather than truncating, negativesqrtpromotes toComplex. No silent wraparound, no silent precision loss. - Real logic programming and goal-oriented planning built in (
rule_add/solve,action_add/plan) — the kind of thing you'd otherwise reach for a dedicated C library (or write from scratch) to get. - Real OS-thread parallelism as one function call (
parallel_map), with no manualpthread_create/mutex bookkeeping, on top of a runtime that's already handled the cross-thread visibility correctness for you. - A genuinely self-hosting compiler. PatLang's own compiler is written in PatLang and compiles itself — you can read and modify the compiler in the same language you write programs in, unlike GCC/Clang's much larger C++ codebases.
- Runtime signals with no manual socket/IPC code. A running program answers a named signal from a second CLI invocation or a network call via three or four function calls — see the signals demo.
See the build daemon exemplar for several of these working together in one real program.
See also
Grammar & Syntax for the full, precise rules. Paradigms Guide for the concurrency model in particular (real threads, cooperative fibers, time-budgeted blocks). Idioms & Patterns covers the value-semantics-vs-handles distinction in more depth. If you know another language too, see PatLang for Python Programmers, PatLang for Java Programmers, or PatLang for Ruby Programmers.