π€ Why MELP?
Every language solves a problem. The problem MELP solves: safety without complexity.
1. The Scope Model β No GC, No Borrow Checker, Memory Safe
In MELP every variable lives inside a scope. When the scope closes, its memory is cleaned up automatically.
scope account
numeric balance = 1000
scope operations
numeric function withdraw(numeric amount)
if amount > balance then return 0 end if
balance = balance - amount
return 1
end function
return withdraw(200)
end scope
end scope
-- balance was cleaned up automatically here
Rust: borrowing rules enforced by the borrow checker.
Go: memory managed by a GC, with pause times.
MELP: scope = lifetime. Neither a GC nor a borrow checker.
Honesty line: the mechanism
is valgrind-proven on the fronts it covers today (big numbers, printed strings).
General string temporaries are not yet under custody and do leak β a known,
addressed limit. And the moment you write external, the guarantee
ends: that is MELP's equivalent of Rust's unsafe.
2. Self-Hosting β The Compiler Is Written in MELP
# The MELP compiler can compile itself:
melp_compiler < main.mlp > stage.ll
clang stage.ll -o new_compiler
./new_compiler < main.mlp > stage2.ll
diff stage.ll stage2.ll # β empty (proof of self-hosting)
This is evidence of the language's maturity and reliability. A bootstrap test exists in every self-hosting language; MELP's difference is that this chain is a mandatory gate on every single change. If the two outputs are not bit-for-bit identical, the change is reverted β no exceptions.
3. Silent Wrongness β Software's Most Dangerous State
The most dangerous state of software is not the state where it crashes. It is the
state where it quietly returns the wrong answer: the billion-dollar mistake
(null), swallowed exceptions, broken pipelines that exit 0,
benchmark loops that -O2 deleted.
MELP's answer is a rule applied throughout the compiler: nothing is left to runtime guesswork. Where another language would pick a plausible interpretation and continue, MELP stops with an explicit error code. Using a decimal without its import is a compile error, not a silent misreading. A missing implementation must fail loudly rather than exit 0.
This discipline is enforced against ourselves as much as against user code: a green result without evidence is treated as more dangerous than a red one.
4. Objects Without OOP β No Inheritance, Composition Instead
struct Point
numeric x
numeric y
end struct
-- point.move(1; 2) β move_point(point; 1; 2)
-- MELP: composition > inheritance
No classes, no inheritance, no virtual methods. Struct + function. Simpler, and faster.
5. The debug Block β A Conversation With the IDE at Design Time
debug
external ide
ide_inspect(members_count)
if members_count > 10000 then
ide_warning("Critical level: " & str(members_count))
ide_highlight(1442)
end if
end debug
Stripped at zero cost in release builds. In debug builds, it talks
to the IDE. Above all it is a letter to the future: a comment may go unread, but a
debug block runs β when the world outgrows the assumption, the program
stops and makes someone read it.
6. Performance β The Same League as C
MELP does not claim to be "faster than C". Its goal is C-league performance without surprises. MELP is compiled with LLVM/clang; the fairest comparison is C compiled with the same backend (clang -O2) β one variable, the language. The numbers follow a protocol (5 runs, best value; Intel i7-10750H).
| Test | MELP | C (clang -O2) | Status |
|---|---|---|---|
| fib(40) | 234 ms | 232 ms | Practically identical β same LLVM (gcc-C: 171 ms) |
| string concat 100K | 9 ms | ~1 ms | O(n) parity; C leads on the constant factor |
fib(40): MELP is also faster than Rust (277 ms) and Go (429 ms). But the headline is not "we beat C" β MELP is in the same league as C compiled with its own backend, without surprises.
Note: side-effect-free loops such as "loop 100M" are folded away by LLVM at compile time (induction variable elimination) β that is an indicator of optimisability, not a runtime speed measurement, and it is excluded from the speed table. That MELP's IR is clean enough for LLVM to fold is a good sign, but it does not mean "we beat C".
MELP vs Other Languages
| Property | MELP | Rust | Go | Zig |
|---|---|---|---|---|
| Memory model | Scope | Borrow checker | GC | Manual |
| Self-hosting | β | β | β | β |
| Data races | β structurally impossible | β borrow checker | β | β |
| debug block (letter to the future) | β | β | β | β |
| Freeze / quarantine | π¬ scope freezing* | β | β | β |
| Without OOP | β | Traits | Interfaces | β |
| Learning curve | Low | High | Medium | Medium |
| Supply chain β package ecosystem | β none exists | cargo | modules | β |
| Supply chain β build chain (xz class) | β no answer | β | β | β |
| Toolchain maturity | β young | β | β | π¬ |
* Freeze works today through a host API (freezing and thawing scopes, selectively); full integration into the language syntax is in development β hence the π¬ (partial) stamp.
The rows we lose stay in the table. A comparison that only lists your wins is an advertisement, not a comparison. Note the build-chain row: nobody has an answer there β MELP included. Having no package ecosystem removes one class of this risk and leaves the other untouched, and MELP being closed source does not help: it removes independent audit, so it lowers verifiability rather than raising it.
Where the Claim Is Aimed
Rust is an enormous competitor in the memory-safety market. But in the market of "let the intent of this code still run forty years from now" and "let a wrong answer never stay silent", there is almost no competition at all. That is where a small language's smartest positioning lies β and it is where MELP aims.
What we have not solved stays on the front page: the honest map lists supply-chain security and toolchain comfort as β, because a claim without an honesty line does not get published.
MELP β Safety without complexity. π