Simple, strongly typed, imperative language for tool/game scripting
Ratchet is a simple, imperative, strongly typed language with familiar C-like syntax that sits between low-level systems languages and high-level scripting languages.
The main idea is simple: make storage and lifetime choices explicit per variable. Instead of hiding allocation behavior behind runtime defaults, Ratchet makes it visible in types so you can reason about where data lives.
At a high level:
T is a stack-allocated value by default.T& is a GC-tracked heap-allocated reference.T* is a non-GC heap-allocated reference with manual lifetime.That model lets you start with straightforward code, then selectively move specific values to GC-tracked or manual heap storage only where performance and allocation behavior matters.
This split can also improve runtime behavior in mixed workloads. If hot paths are migrated away from GC-tracked storage and into manually managed storage, the collector has fewer objects and references to scan. In practice, that can reduce GC traversal work and make collection pauses smaller or less frequent.
This keeps the workflow ergonomic for infrequently ran code, while allowing for more precise control where it matters.
Ratchet is still being actively built and is not fully working yet. To try existing pieces, use the 0.0.5 proof-of-concept release, knowing only part of the language works there.
The long-term runtime direction is interpreted execution first, with a planned JIT and a possible optional AOT path later.
This document is the main language overview for now.
Ratchet uses familiar C-like structure.
fn and struct declarations.;.{ ... }.Type name = expression;.Quick look:
int score = 42;
if (score > 10) {
echo score;
}
boolintfloatdoublestringnull (used for no-return function signatures)struct value types& and *One complete function example:
fn int clamp(int value, int minV, int maxV) {
if (value < minV) {
return minV;
}
if (value > maxV) {
return maxV;
}
return value;
}
fn bool program() {
int raw = 120;
int safe = clamp(raw, 0, 100);
echo safe;
return true;
}
General shape:
fn <return-type> <name>(<typed-params>) {
// body
}
Notes:
null is used for functions that do not return a value.T& or T*).Ratchet makes storage mode explicit in type spelling.
| Form | Meaning | Allocation | Copy behavior |
|---|---|---|---|
T |
Value type | Stack/inline (default) | Full value copy |
T& |
GC-managed heap-allocated reference | new T& |
Reference copy |
T* |
Manual heap-allocated reference | new T* |
Reference copy |
Quick examples:
int a = 5; // stack value (copied)
int& b = {5}; // heap-allocated, GC-tracked
int* c = {5}; // heap-allocated, non-GC-tracked
Notes:
T, T&, and T* are distinct and not implicitly convertible.T* values must be explicitly freed.Array forms (using Vec2):
Vec2[4] a = Vec2[4]; // stack-allocated array, size must be known at compile time
Vec2[]& c = new Vec2[4]&; // GC-tracked array reference
Vec2[]* d = new Vec2[4]*; // non-GC-tracked array reference
Vec2&[]& e = new Vec2&[5]&; // GC-tracked array of GC-tracked Vec2 references
in and inout are keywords for explicit borrow-style parameter passing in free functions.
Intent:
in T p means a read-only borrow.inout T p means a mutable borrow.inout arguments cannot alias in the same call.Syntax:
struct Vec2 {
float x;
float y;
}
fn null translate(inout Vec2 v, float dx, float dy) {
v.x = v.x + dx;
v.y = v.y + dy;
}
struct values are still plain value types.
struct Vec2 {
float x;
float y;
}
Methods are intended as an alternative call style over free functions, not a separate ownership model. In other words, they are syntax sugar over the same core parameter-passing rules.
Conceptual sugar direction:
// method style
method null translate(float dx, float dy)
// equivalent free-function style
fn null Vec2_translate(inout Vec2 self, float dx, float dy)
Interfaces are part of the language direction as compile-time contracts.
interface HasPosition {
field float x;
field float y;
method float length2D() {
return sqrt(x*x + y*y);
}
}
fn bool program() {
echo 1;
return true;
}
fn bool program() {
int a = 10;
int b = 20;
int c = a + b;
bool ok = c > 10;
echo c;
return ok;
}
Vec2)struct Vec2 {
float x;
float y;
method null translate(float dx, float dy) {
x = x + dx;
y = y + dy;
}
}
fn bool program() {
Vec2 p = { x = 1.0f, y = 2.0f };
p.translate(3.0f, -1.0f);
return true;
}
struct Enemy {
int hp;
}
fn bool program() {
Enemy& tracked = new Enemy& { hp = 100 };
Enemy* manual = new Enemy* { hp = 50 };
free(manual);
return true;
}