Skip to content

Symbol Noise ​

How many special characters clutter each line of code?

"Symbol noise" (formally: sigil density) counts non-alphanumeric, non-whitespace characters per line. Think: & * < > :: -> => ? ! ; : { } [ ].

Why it matters ​

Every special character is a micro-decision for the reader: what does this symbol mean in this context? Languages that overload symbols (& means reference AND bitwise-AND AND pattern-binding in Rust) impose more cognitive work per character.

Results ​

Language ↕Avg Symbols/Line ↑Avg Unique Symbol Types ↕
Csharp★3.8▼★14▼
Go★4.2▼★16▼
Ruby★4.3▼★14▼
Swift★4.3▼★15▼
Haskell★4.4▼★15▼
Kotlin★4.6▼★15▼
Milo★4.9▼★16▼
Python★4.9▼★12▼
C★5.3▼★21▼
Clojure★5.3▼★8▼
Java★5.6▼★17▼
Elixir★5.7▼★15▼
Javascript★5.8▼★15▼
Rust★5.9▼★17▼
Cpp★6.2▼★19▼
Typescript★6.2▼★17▼
Zig★6.4▼★19▼
Objc★6.6▼★19▼
Erlang★6.7▼★17▼

The two dimensions of noise ​

Symbols per line (density) — how cluttered does each line look?

Unique symbol types (vocabulary) — how many different squiggles do you need to learn?

These don't always correlate. Haskell has low density (4.6/line) AND low vocabulary (14 types) — few symbols used sparsely. Elixir has high density (6.4/line) but moderate vocabulary (15 types) — a few symbols (|>, &) used heavily.

Why each language is noisy (or not) ​

Rust's noise is safety-related. The &, mut, Some(), unwrap(), lifetime annotations — they encode ownership and borrowing. Each symbol carries real semantic weight.

TypeScript's noise is syntactic. Generics (<number, number>), non-null assertion (!), optional chaining (?.) — these serve the type checker, not runtime behavior.

Elixir's noise is pipeline-driven. The |> operator, pattern matching ({:ok, val}), anonymous functions (&(&1 + 1)) — dense but consistent.

Go avoids symbols by using words. make() instead of {}, append() instead of .push(). Lower symbol density, but more lines of code.

Ruby minimizes both. Blocks (do |x| ... end), English-like methods (empty?, puts, each), implicit returns — code reads almost like prose.

Key insight

Cognitive load scales with symbol variety (how many different symbols to learn), not symbol frequency (how often they appear). Seeing &&& is fine if & always means one thing. Seeing & &mut &'a *const *mut is five concepts in similar-looking syntax — that's expensive.

What counts as a symbol?

Everything that isn't a letter, digit, or whitespace: + - * / % = == != < > <= >= && || ! ~ ^ & | ; : , . :: -> => .. ..= ? # @ ' " ( ) [ ] { } < >

We count both total symbols per line (density) and unique symbol types per program (vocabulary).