Website | Source | Handmade Project (website)
C3 is a programming language that builds on the syntax and semantics of the C language, with the goal of evolving it while still retaining familiarity for C programmers.
It's an evolution, not a revolution: the C-like for programmers who like C.
Design Principles
C3 owes its inspiration to the C2 language: to iterate on top of C without trying to be a whole new language.
In what ways does C3 differ from C?
Stack module
module stack {Type};
// Above: the parameterized type is applied to the entire module.
struct Stack
{
usz capacity;
usz size;
Type* elems;
}
// The type methods offers dot syntax calls,
// so this function can either be called
// Stack.push(&my_stack, ...) or
// my_stack.push(...)
fn void Stack.push(Stack* this, Type element)
{
if (this.capacity == this.size)
{
this.capacity *= 2;
if (this.capacity < 16) this.capacity = 16;
this.elems = realloc(this.elems, Type.sizeof * this.capacity);
}
this.elems[this.size++] = element;
}
fn Type Stack.pop(Stack* this)
{
assert(this.size > 0);
return this.elems[--this.size];
}
fn bool Stack.empty(Stack* this)
{
return !this.size;
}
Using the stack:
import stack;
// Define our new types, the first will implicitly create
// a complete copy of the entire Stack module with "Type" set to "int"
alias IntStack = Stack {int};
// The second creates another copy with "Type" set to "double"
alias DoubleStack = Stack {double};
// If we had added "alias IntStack2 = Stack {int}"
// no additional copy would have been made (since we already
// have an parameterization of Stack {int} so it would
// be same as declaring IntStack2 an alias of IntStack
// Importing an external C function is straightforward
// here is an example of importing libc's printf:
extern fn int printf(char* format, ...);
fn void main()
{
IntStack stack;
// Note that C3 uses zero initialization by default
// so the above is equivalent to IntStack stack = {};
stack.push(1);
// The above can also be written IntStack.push(&stack, 1);
stack.push(2);
// Prints pop: 2
printf("pop: %d\n", stack.pop());
// Prints pop: 1
printf("pop: %d\n", stack.pop());
DoubleStack dstack;
dstack.push(2.3);
dstack.push(3.141);
dstack.push(1.1235);
// Prints pop: 1.123500
printf("pop: %f\n", dstack.pop());
}
Last modified 18 May 2025