Skip to content

// BASIC · SINCLAIR + C64 //

What You're Allowed to Call Things

On the Spectrum a string variable must be one letter. On the C64, speed and spell are the same variable. Both rules are a ROM showing through.

Type LET name$ = "Sam" into a ZX Spectrum and it will not even take the line. The cursor stops at the $ and turns into a flashing ?, and there it sits. Not a typo, not a missing quote — the machine genuinely will not let a string variable have a name longer than one letter. n$ is fine. a$ is fine. name$ is illegal, and the machine is certain of it. The first time it happens it feels like a bug in the interpreter. It’s the opposite: it’s the interpreter being ruthlessly consistent about something it decided in 1982.

A ZX Spectrum screen showing LET name?$="Sam" with a question mark marking the error before the dollar sign
The line is refused. The ? is the error marker, sitting exactly where the parser gave up, and the trailing L is the mode cursor still waiting. The report behind it is never printed.
A ZX Spectrum screen showing the report 0 OK, 0:1 after a single-letter string assignment
The same statement with a one-letter name. LET n$ = "Sam" is accepted and runs, and the machine says so.

Two rules that look like fussiness

Sinclair BASIC draws a hard line between numbers and strings. A numeric variable can have a long, readable name — score, lives, level all work. A string variable cannot: it must be a single letter followed by $. There is no name$, no player$, no score$. One letter, or nothing.

The machine won’t say why, and it knows exactly why. The syntax checker reads name as a perfectly legal long numeric name, hits a $ it has no grammar for, and raises the error the ROM calls report C — “Nonsense in BASIC”. You never see those words. While a line is being syntax-checked the Spectrum prints only the error marker and keeps the report behind it to itself, so the entire diagnosis reaches you as one flashing question mark. Reach for an unassigned long string a different way, at run time, and you’ll get “Variable not found” instead — same underlying rule, different symptom, and neither of them ever says the actual thing, which is strings only get one letter.

There’s a companion rule that feels equally arbitrary until you see it’s the same rule. FOR loops demand a single-letter control variable too: FOR i = 1 TO 10 runs; FOR speed = 1 TO 10 is refused on the spot, same marker, same silence. Long numeric names are legal in general but not here. Why would a FOR loop care how long the name is?

All the way down, it’s one byte

Because to the ROM, a single-letter variable and a multi-letter variable are different kinds of thing, tagged differently the moment they’re recognised. The 48K ROM’s variable-lookup routine (LOOK-VARS, at $28B2) classifies every name it reads and stores a discriminator in the C register — the top bits encode what type of variable this is, and single-letter numerics get their own encoding distinct from long names, string variables, and arrays.

FOR loops route their control variable through the syntax class the ROM calls CLASS-04, and CLASS-04’s check is tiny and unforgiving. It takes that discriminator and does, in effect, OR $9F then INC A and errors unless the result is zero — which only comes out zero when two specific bits are both set, i.e. when the variable is a single-letter numeric. Anything else — a long name, a string — fails the comparison and you get “Nonsense in BASIC.” The naming rule you keep tripping over isn’t a style guide the manual is enforcing. It’s the shape of one bitwise test in a syntax checker, and you can read the exact instructions that make it true.

That’s the “see all the way down” moment I keep chasing on these machines: a rule that feels like the language being precious turns out to be a single OR/INC/compare in ROM, put there because single-letter variables were cheaper to store and find, and the whole grammar was built around that saving.

The C64 forgets instead of forbidding

Commodore made the same underlying decision — names cost memory, store them cheaply — and it leaks in the opposite, sneakier direction. The C64 doesn’t forbid long names. It ignores the ends of them. Only the first two characters are significant, so speed and spell are the same variable, silently sharing one slot. So are lives and limit, player and place. No error, no warning — you assign to one and read what looks like a different variable and get the first one’s value, and the machine considers this a completely reasonable thing to have done to you.

A Commodore 64 screen where SPEED is set to 5 and PRINT SPELL then prints 5
Assign to SPEED, print SPELL, get 5. Two names, two letters in common, one variable.

Two machines, two ways the same fact surfaces. The Spectrum makes the constraint loud — it refuses the name outright, so at least you know. The C64 makes it quiet — it accepts the name, keeps two letters of it, and lets you find out the hard way when two variables start haunting each other. Neither is arbitrary. Both are a symbol table that was built small, showing through the language that sits on top of it.

Your names have a budget too

The rules for what you’re allowed to call things are never about taste, on any system. They’re the symbol table’s limits wearing a style-guide costume. Identifier length caps, reserved words you can’t use, case sensitivity or the lack of it, the maximum nesting of a name — every one of them is some storage or lookup decision from the language’s implementation, made permanent because it shipped. Modern languages hide the budget better; they rarely refuse a long name or silently merge two. But the shape is identical, and the old micros are where you can still see it — where “you can’t call it that” resolves, if you follow it down far enough, to a single comparison in a ROM you’re allowed to read.


The Spectrum’s single-letter rule shows up first in the BASIC track’s early units; the C64’s two-character collision is designed around in the C64 BASIC volume. The ROM detail is from the disassembled 48K ROM (LOOK-VARS / CLASS-04).