Introducing em—dash
a heartfelt apology
I sent an apology to my friend Joe last week. It opens:
I owe you one. I have been drafting this letter since 2024–25, rewriting every half-finished, half-honest version before this one. The truth — and I say this with my whole chest — is that I treated you badly.
It's at least a full page long. Full remorse. Napkin math concluding the fault splits 100–0 against me. A standing offer to be judged not by my words, but by the record.
Also, the letter is nonsense. I don't owe Joe anything (to my knowledge?) What I actually share with Joe is the same nerdy dry sense of humor.
Because in reality, it's a hidden program. If you run it, the apology letter does this:
I should back up.
The AI tell
At some point in the last year, the em-dash went from an elegant punctuation mark — like this — to an obvious indicator that AI is responsible for the words you're reading. I've loved the em dash since long before it became a fingerprint. Now, every '—' I type arrives pre-incriminated.
So I leaned all the way in. If my favorite punctuation mark is machine code now, fine. Let's make it machine code.
Enter em—dash
em—dash is an esoteric programming language in which the dashes are the entire syntax. Every character that is not a dash is a comment. The words are decoration. The punctuation is the program. Which means a tweet, a LinkedIn thinkpiece, or a heartfelt apology can quietly be executable.
An alphabet of three line segments
The whole character set is three lengths of horizontal line.
That hierarchy is the design principle. Hyphens are cheap, so they do the bulk hauling. Em dashes are common enough to be structural and distinctive enough to mean something. En dashes are precious — real prose barely uses them — so they get the rare, decisive jobs, like slamming a number shut.
(macOS will sell you the whole alphabet: - is a hyphen, option+- is an en dash, option+shift+- is an em dash. Now you're armed.)
Twenty opcodes, zero delimiters
Under the punctuation, it's a stack machine, in the proud tradition of Whitespace. Opcodes are short sequences of the three symbols, and the code is prefix-free: no opcode is the beginning of any other. That's the entire parser. No delimiters, no spaces — the dashes just stream in, and the moment a sequence matches, an instruction fires.
Read it left to right: --- duplicates the top of the stack, -—- adds, –-- opens a loop. A lone — is special: it doesn't run anything — it opens a number.
How punctuation becomes a number
After that opening em dash, the machine reads dashes as bits: hyphen is 0, em dash is 1, and an en dash says the number is over. Then the value lands on the stack, where an instruction like OUTC (output character) can spend it.
Here's the language's "hello world" program, which prints "!" (codepoint 33):
My editor sighed — again — at my low-key, half-baked, semi-ironic, over-long sentences — circa 2024 – my self-styled, 2013–14-ish voice.
Click the toggle. The complaining evaporates and eleven dashes remain — and eleven dashes are two instructions:
A sentence complaining about its own punctuation, and the punctuation spends the whole time printing an exclamation point. Note the en dash drifting after "circa 2024" like a misplaced British parenthetical — that's the terminator. Every flourish is doing a job.
And because every non-dash character is a comment — even in the middle of an opcode — an instruction can be smeared across half an essay. The words can say anything. This is the load-bearing trick.
The apology, disassembled
Now you can read my letter the way the machine does. Hover the dashes:
I owe you one. I have been drafting this letter since 2024–25, rewriting every half-finished, half-honest version before this one. The truth — and I say this with my whole chest — is that I treated you badly. I was self-absorbed, short-tempered, and thin-skinned. You deserved better — so much better — than what I gave. What I gave was second-rate.
For 18–19 months I let my self-importance run the show. From May–June of last year especially, I was flat-out unbearable. …
Sixteen instructions total. Here is the entire letter, in its entirety. And as the machine reads it:
3:59 LOOP 4:69 PUSH 70 F 9:31 OUTC 10:64 PUSH 85 U 13:62 OUTC 16:29 PUSH 67 C 19:35 OUTC 22:23 PUSH 75 K 26:5 OUTC 29:18 PUSH 89 Y 32:44 OUTC 35:26 PUSH 79 O 41:5 OUTC 42:19 PUSH 85 U 45:14 OUTC 46:32 END
Ninety dashes spread over two thousand characters of remorse, and every single word is a comment.
The duplicitous hyphen
There's a second tier for people who find prose inefficient: exotic Unicode dashes that each alias an entire opcode. One character, one instruction. My favorites:
Every other dash in Unicode is reserved (as much as you can reserve characters for yourself). Using one is a lexer error with a bespoke diagnostic — U+1806 MONGOLIAN TODO SOFT HYPHEN is reserved; this program is too powerful.
Handle with care
A language made of punctuation is fragile in ways no other language gets to be. Unicode normalization — the tidying that text pipelines do constantly, silently — will quietly swap the duplicitous hyphen for a plain one and change what your program does. Some editors substitute dashes on paste. So the toolchain ships a dump command that names every dash's codepoint, one per line, for debugging by squinting.
The confession inside the confession
Of course I didn't write the apology. I wrote this:
loop say "FUCKYOU" end
The assembler turns that into the ninety dashes. Then I handed the dash sequence to Claude — the very LLM whose em-dash habit started the whole discourse — and asked it to write a sincere apology around them: every dash in order, no extras, prose that scans like a person at their lowest. There's a verify tool that checks a draft against the target program, dash by dash, so the model can iterate until:
draft realizes the target program: all 90 dashes correct. Send it.
This is constrained writing — the same family as lipograms and Oulipo — and it turns out LLMs are unsettlingly good at it.
A Heartfelt Apology
I can't commit to a prank. I sent the fake apology letter to Joe, and immediately followed up with what it was actually about.
I also didn't write this esolang from scratch. This was an evening project playing around with Claude Fable 5. Around a half-hour of back-and-forth discussion with the model, and then asking if Fable could write the whole thing at once. And it did.
One day later, the US Government banned Fable 5, citing "national security". I'm not gonna comment on that, other than to say that it was probably my fault for asking it to write a joke programming language that uses em-dashes as syntax.
The interpreter, the spec, the assembler, and the complete apology live on GitHub: em—dash. I have no future plans for it. It's a joke, a puzzle, and a love letter to the em dash. But if you do find a use for it, or write something fun with it, let me know!