Why Argentum Has Optional Semicolons (And Why That’s a Design Statement)

A Language Built for Safety and Humans

Argentum is not a typical programming language. It was designed from the ground up to eliminate entire categories of bugs — no deadlocks, total memory, type, null, const etc. safety. AFAIK it's the only practical programming language with formal proof of absence of memory leaks That alone would make it interesting.

But Argentum has a second, quieter ambition: the syntax should get out of your way. The code you read should look like the intent you had, not like you're filing paperwork with the compiler. For example variable declarations are a=Point(1,42) not let mut x = Rc::new(RefCell::new(Point { ... }));... Argentum is designed to systematically eliminate that noise.


"Wait — Why Does It Have Semicolons?"

Every time Argentum is demoed to engineers and language nerds, someone asks it. Not "how does the ownership model work" or "what's the concurrency story" — but: "why does it have semicolons?"

That question is actually a good instinct. Semicolons are a proxy question for: "how much does this language trust me as a developer?" A language that requires you to terminate every statement with ; is a language whose parser needs hand-holding. It's a language where the grammar and the human can't agree on where a thought ends.

The answers, by the way, are: yes, it trusts, and no it doesn't require semicolons. Not anymore. Semicolons are now entirely optional in Argentum — and so are commas. But to appreciate why that matters, let's look at how other languages handle the same problem, and why they mostly get it wrong.


How Other Languages Try to Avoid Semicolons

Every popular language has confronted this. The solutions range from elegant to genuinely treacherous.

Python uses indentation as syntax. It works — mostly. But Python draws a line between single-line and multi-line modes. Inside parentheses, you get implicit line continuation. Outside them, you need a backslash to escape a newline. The result is two mental models coexisting in the same file. It's coherent, but it's not unified.

Go takes a different approach: the compiler secretly injects semicolons for you at the end of certain lines, based on what token ends the line. This sounds convenient until you hit the consequences. Because the compiler inserts a semicolon after the closing brace of a function signature, Go requires you to put the opening { on the same line. No choice. And in some contexts, Go forces you to add trailing commas just to prevent the injected semicolon from landing in the wrong place. You occasionally get error messages like "unexpected semicolon" in code that contains no semicolons. You're debugging the compiler's invisible edits to your source.

JavaScript has ASI — Automatic Semicolon Insertion — and it is a famously sharp edge. The rules are complex enough that even experienced JS developers keep a cheat sheet. The canonical horror: a return statement followed by a newline silently returns undefined, because ASI inserts a semicolon right after return. Your function lies to you and the compiler helps it do it. The JS community largely responded by adopting linters that enforce explicit semicolons everywhere — which means the "automatic" in ASI was mostly a trap.

The pattern here is telling. Each of these languages treats newlines as an afterthought — something to paper over or inject around. The grammar was designed first for a flat token stream, and newline handling was bolted on.


How Argentum Does It

Argentum's approach starts from a different premise: newlines are a first-class part of the grammar.

This is made tractable by one of Argentum's core design choices — the language has no statements, only expressions. That single constraint simplifies the grammar enough that the parser can always determine unambiguously whether a newline is a separator or just whitespace. No injection, no context-sensitive hacks, no hidden rules.

The basic rule is direct: wherever the grammar accepts a ; or ,, a newline works identically. You can still write the punctuation if you want — to put multiple things on one line — but you never have to:

{
    doSomething()
    x += 10
    doSomethingElse()
}

There's one genuine edge case: what if a line starts with an operator like -, &, *, ?,~ or ? Is it continuing the previous expression, or starting a new one? Argentum resolves this with a whitespace rule that matches how readable code looks anyway:

  • + value — space after the operator → binary infix, continues the previous expression
  • +value — no space → unary prefix, starts a new expression

And opening brackets (, {, [ at the start of a line always begin a fresh expression. Never a continuation. This eliminates the "defensive semicolons" pattern you see in JavaScript codebases.

The result: what you see is what the compiler compiles. No invisible semicolons, no escape hatches, no mode switches.


The Same Logic Applies to Commas

Long parameter lists are where syntactic punctuation hurts most. Commas between parameters are semantic noise — the newline already tells you where one argument ends and the next begins.

With Argentum's optional commas, you can lay out a call site the way you'd structure a thought:

someFunction(
    x, y, z  // group small, related params on one line
    width    // larger or documented param on its own
    height
    callback // no trailing comma needed
)

Notice what's also possible here: comments between arguments, without any syntactic contortion. In most languages, inserting a comment between parameters requires careful comma placement. In Argentum, the grammar doesn't need punctuation to "protect" the structure around a comment. The newlines carry the structure; comments are just text.


This Works Everywhere in the Language

This isn't a special case for function calls. The same rules apply uniformly — in imports, class definitions, function signatures, expressions:

using sys {
   log              // in name imports
   StrBuilder
}
using string  // in usings
using utils{ forRange }
const LF = utf32_(10) // in constants

fn numAndText(
   a int       // in function definitions
   b str
) str {
   "{a}-{b}{LF}"
}

class Point {
   x=0            // in class fields or bases
   y=0
}

b = StrBuilder // in locals' declarations
forRange(
   1            // in function calls
   101
) {
   _ % 3 == 0 ? b.putStr("fizz")   // and sequential operations
   _ % 5 == 0 ? b.putStr("buzz")
   b.pos == 0 ? b.putInt(_)
   log(b.newLine().toStr())
}

One rule. Applied everywhere. No special cases to memorize.

There's also a clean way to control what a block returns. In Argentum, a block evaluates its expressions in sequence and returns the last one. To explicitly return nothing, you have two options — a trailing semicolon (explicit void signal), or ending the block with {} (an empty block produces void). Both are readable, both are intentional, neither requires a comment to explain itself.

// classic: trailing semicolon as an explicit void signal
{ x += 10; }

// new way: end with an empty block — {} produces void
{
    doSomething()
    x += 10
    doSomethingElse()
    {} // return nothing, and not a result of doSomethingElse()
}

What's This Actually For?

Three audiences benefit from this, and it's worth naming them separately.

For the human developer: less punctuation means less time scanning for missing semicolons, less time arguing about trailing commas in code review, and less cognitive overhead per line. You read code more than you write it — every removed token that carries no meaning is a small, permanent improvement to readability.

For the codebase at scale: uniform, minimal syntax ages well. Punctuation-heavy code develops inconsistencies — some files use trailing commas, some don't; some functions have single-line signatures, some multi-line. When the grammar accepts both equally, those style debates become irrelevant. The diff noise goes away. Diffs don't poison the surrounding lines with injected/removed commas and semicolons.

For AI coding agents: this one matters more than it might seem. LLMs work with token budgets. Every ; and , in a source file is a token that carries no semantic information about what the program does — it only satisfies the parser. A language where those tokens are optional produces smaller, denser representations of the same program. That's not a minor optimization; for code generation at scale, it's a meaningful reduction in the surface area the model needs to manage.


Argentum's optional semicolons and commas are not a cosmetic feature. They're the natural consequence of designing a grammar that respects newlines from the start, rather than treating them as a problem to work around after the fact. The language was already unambiguous. Making punctuation optional just let the syntax catch up to what the grammar already knew.

Leave a Reply

Your email address will not be published. Required fields are marked *